diff --git a/accounting/decimal.go b/accounting/decimal.go index bb01f28..068f97f 100644 --- a/accounting/decimal.go +++ b/accounting/decimal.go @@ -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) } diff --git a/accounting/decimal_test.go b/accounting/decimal_test.go index af46dd4..1f5706a 100644 --- a/accounting/decimal_test.go +++ b/accounting/decimal_test.go @@ -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()) diff --git a/accounting/test/decimal.go b/accounting/test/decimal.go index 1e0e94b..ee4293c 100644 --- a/accounting/test/decimal.go +++ b/accounting/test/decimal.go @@ -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()) diff --git a/bearer/bearer.go b/bearer/bearer.go index aaea6c3..429e0d6 100644 --- a/bearer/bearer.go +++ b/bearer/bearer.go @@ -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 { - return b.eaclTable - } - - return eacl.Table{} +func (b *Token) EACLTable() *eacl.Table { + return b.eaclTable } // 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 { diff --git a/bearer/bearer_test.go b/bearer/bearer_test.go index 5948bad..3753bc6 100644 --- a/bearer/bearer_test.go +++ b/bearer/bearer_test.go @@ -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)) } diff --git a/bearer/test/generate.go b/bearer/test/generate.go index 4f5dd3d..f87bd68 100644 --- a/bearer/test/generate.go +++ b/bearer/test/generate.go @@ -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 } diff --git a/checksum/checksum.go b/checksum/checksum.go index 37238af..5ef54c7 100644 --- a/checksum/checksum.go +++ b/checksum/checksum.go @@ -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() diff --git a/checksum/checksum_test.go b/checksum/checksum_test.go index 9da857d..247deef 100644 --- a/checksum/checksum_test.go +++ b/checksum/checksum_test.go @@ -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) { diff --git a/checksum/example_test.go b/checksum/example_test.go index d98c992..8d12409 100644 --- a/checksum/example_test.go +++ b/checksum/example_test.go @@ -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[:]) diff --git a/checksum/test/generate.go b/checksum/test/generate.go index d8c6b0b..171ee65 100644 --- a/checksum/test/generate.go +++ b/checksum/test/generate.go @@ -13,7 +13,7 @@ func Checksum() checksum.Checksum { rand.Read(cs[:]) - var x checksum.Checksum + x := checksum.NewChecksum() x.SetSHA256(cs) diff --git a/client/accounting.go b/client/accounting.go index 71dd030..aa4c9a9 100644 --- a/client/accounting.go +++ b/client/accounting.go @@ -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 diff --git a/client/api.go b/client/api.go index dd18c42..101e99d 100644 --- a/client/api.go +++ b/client/api.go @@ -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) } diff --git a/client/client.go b/client/client.go index 3942390..f1c5e2b 100644 --- a/client/client.go +++ b/client/client.go @@ -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" diff --git a/client/client_test.go b/client/client_test.go index 16f66e2..92395ea 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -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 { diff --git a/client/common.go b/client/common.go index 1d56130..c11a0ab 100644 --- a/client/common.go +++ b/client/common.go @@ -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 { diff --git a/client/container.go b/client/container.go index aad23cd..86fabda 100644 --- a/client/container.go +++ b/client/container.go @@ -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) diff --git a/client/container_delete.go b/client/container_delete.go index 0059988..06644c0 100644 --- a/client/container_delete.go +++ b/client/container_delete.go @@ -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 diff --git a/client/container_eacl.go b/client/container_eacl.go index 8f8e651..b8e07da 100644 --- a/client/container_eacl.go +++ b/client/container_eacl.go @@ -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") } diff --git a/client/container_get.go b/client/container_get.go index 9e98523..8230d0a 100644 --- a/client/container_get.go +++ b/client/container_get.go @@ -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 } diff --git a/client/container_list.go b/client/container_list.go index eb8cc88..39e444e 100644 --- a/client/container_list.go +++ b/client/container_list.go @@ -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) } diff --git a/client/container_put.go b/client/container_put.go index 630d265..1da42a7 100644 --- a/client/container_put.go +++ b/client/container_put.go @@ -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 diff --git a/client/container_set_eacl.go b/client/container_set_eacl.go index 1917373..ba09ffe 100644 --- a/client/container_set_eacl.go +++ b/client/container_set_eacl.go @@ -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 diff --git a/client/container_space.go b/client/container_space.go index af984e5..b5ff5e2 100644 --- a/client/container_space.go +++ b/client/container_space.go @@ -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 } diff --git a/client/netmap.go b/client/netmap.go index b63ba65..d96db63 100644 --- a/client/netmap.go +++ b/client/netmap.go @@ -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) } diff --git a/client/netmap_test.go b/client/netmap_test.go index 76920a1..726566c 100644 --- a/client/netmap_test.go +++ b/client/netmap_test.go @@ -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) diff --git a/client/object_delete.go b/client/object_delete.go index 873cf3d..a8fd2e9 100644 --- a/client/object_delete.go +++ b/client/object_delete.go @@ -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) } diff --git a/client/object_get.go b/client/object_get.go index 02de74a..04c9fa0 100644 --- a/client/object_get.go +++ b/client/object_get.go @@ -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 { diff --git a/client/object_hash.go b/client/object_hash.go index 6df0d7a..4fafda7 100644 --- a/client/object_hash.go +++ b/client/object_hash.go @@ -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) } diff --git a/client/object_put.go b/client/object_put.go index 2861ea4..56dcc04 100644 --- a/client/object_put.go +++ b/client/object_put.go @@ -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. diff --git a/client/object_put_raw.go b/client/object_put_raw.go index 64cb250..ecf8fb1 100644 --- a/client/object_put_raw.go +++ b/client/object_put_raw.go @@ -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) } diff --git a/client/object_put_single.go b/client/object_put_single.go index 4ed03a6..6a644ec 100644 --- a/client/object_put_single.go +++ b/client/object_put_single.go @@ -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 { diff --git a/client/object_search.go b/client/object_search.go index 95c18ab..6ddbe82 100644 --- a/client/object_search.go +++ b/client/object_search.go @@ -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 { diff --git a/client/object_search_test.go b/client/object_search_test.go index f449d61..8b23143 100644 --- a/client/object_search_test.go +++ b/client/object_search_test.go @@ -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) diff --git a/client/response.go b/client/response.go index e1a702e..5ac592e 100644 --- a/client/response.go +++ b/client/response.go @@ -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. diff --git a/client/session.go b/client/session.go index 3e1180e..2d435ce 100644 --- a/client/session.go +++ b/client/session.go @@ -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 } diff --git a/client/status/common.go b/client/status/common.go index 421d532..28d610f 100644 --- a/client/status/common.go +++ b/client/status/common.go @@ -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() } diff --git a/client/status/common_test.go b/client/status/common_test.go index d66b5b5..510951e 100644 --- a/client/status/common_test.go +++ b/client/status/common_test.go @@ -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()) }) } diff --git a/client/status/container.go b/client/status/container.go index c62aaac..301e74f 100644 --- a/client/status/container.go +++ b/client/status/container.go @@ -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 } diff --git a/client/status/object.go b/client/status/object.go index 579cb93..f52ac78 100644 --- a/client/status/object.go +++ b/client/status/object.go @@ -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 } diff --git a/client/status/object_test.go b/client/status/object_test.go index 8472093..5baadd4 100644 --- a/client/status/object_test.go +++ b/client/status/object_test.go @@ -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) diff --git a/client/status/session.go b/client/status/session.go index 6c54965..149ec5f 100644 --- a/client/status/session.go +++ b/client/status/session.go @@ -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 } diff --git a/client/status/success.go b/client/status/success.go index a68983d..36f1811 100644 --- a/client/status/success.go +++ b/client/status/success.go @@ -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) diff --git a/client/status/unrecognized.go b/client/status/unrecognized.go index b9a8cdb..1052c37 100644 --- a/client/status/unrecognized.go +++ b/client/status/unrecognized.go @@ -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) } diff --git a/client/status/v2.go b/client/status/v2.go index ff6ccec..05b60e2 100644 --- a/client/status/v2.go +++ b/client/status/v2.go @@ -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 } diff --git a/client/status/v2_test.go b/client/status/v2_test.go index 14d4c30..0cdb754 100644 --- a/client/status/v2_test.go +++ b/client/status/v2_test.go @@ -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)) } } } diff --git a/container/container.go b/container/container.go index 9c6c0f8..1bf79db 100644 --- a/container/container.go +++ b/container/container.go @@ -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()) } diff --git a/container/container_test.go b/container/container_test.go index f0a2244..e84fe3e 100644 --- a/container/container_test.go +++ b/container/container_test.go @@ -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)) } diff --git a/container/id/id.go b/container/id/id.go index bde739c..f411bef 100644 --- a/container/id/id.go +++ b/container/id/id.go @@ -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[:]) } diff --git a/container/id/id_test.go b/container/id/id_test.go index ad12295..aa05a3e 100644 --- a/container/id/id_test.go +++ b/container/id/id_test.go @@ -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)) }) } diff --git a/container/network.go b/container/network.go index b9a9e38..51ba0da 100644 --- a/container/network.go +++ b/container/network.go @@ -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) } diff --git a/container/network_test.go b/container/network_test.go index 38e24f2..a06b202 100644 --- a/container/network_test.go +++ b/container/network_test.go @@ -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)) }) diff --git a/container/size.go b/container/size.go index 64220ed..45915d6 100644 --- a/container/size.go +++ b/container/size.go @@ -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)) } diff --git a/container/size_test.go b/container/size_test.go index 77fed4d..45413dc 100644 --- a/container/size_test.go +++ b/container/size_test.go @@ -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) diff --git a/container/test/generate.go b/container/test/generate.go index 65b03a8..799f5e0 100644 --- a/container/test/generate.go +++ b/container/test/generate.go @@ -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) diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go index 095cdd9..8062fad 100644 --- a/crypto/crypto_test.go +++ b/crypto/crypto_test.go @@ -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)) diff --git a/crypto/doc.go b/crypto/doc.go index 8b568f5..ab1bec2 100644 --- a/crypto/doc.go +++ b/crypto/doc.go @@ -40,7 +40,7 @@ On server side: // recv msg - var sig frostfscrypto.Signature + sig := frostfscrypto.NewSignature() sig.ReadFromV2(msg) // process sig diff --git a/crypto/signature.go b/crypto/signature.go index 33c6132..df77461 100644 --- a/crypto/signature.go +++ b/crypto/signature.go @@ -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()) } diff --git a/crypto/signer.go b/crypto/signer.go index 9f99e3d..64ea2e4 100644 --- a/crypto/signer.go +++ b/crypto/signer.go @@ -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. diff --git a/eacl/enums.go b/eacl/enums.go index b2b5353..7fe434c 100644 --- a/eacl/enums.go +++ b/eacl/enums.go @@ -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) diff --git a/eacl/enums_test.go b/eacl/enums_test.go index 29f2518..2af6b43 100644 --- a/eacl/enums_test.go +++ b/eacl/enums_test.go @@ -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) }) } diff --git a/eacl/filter.go b/eacl/filter.go index 4403e5a..a5a6311 100644 --- a/eacl/filter.go +++ b/eacl/filter.go @@ -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 } diff --git a/eacl/filter_test.go b/eacl/filter_test.go index 74b9a10..cf25877 100644 --- a/eacl/filter_test.go +++ b/eacl/filter_test.go @@ -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) { diff --git a/eacl/record.go b/eacl/record.go index 0762ef3..9c89998 100644 --- a/eacl/record.go +++ b/eacl/record.go @@ -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 } diff --git a/eacl/record_test.go b/eacl/record_test.go index 0bdc37f..2880972 100644 --- a/eacl/record_test.go +++ b/eacl/record_test.go @@ -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", }, } diff --git a/eacl/table.go b/eacl/table.go index b16467b..625c15d 100644 --- a/eacl/table.go +++ b/eacl/table.go @@ -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) } diff --git a/eacl/table_test.go b/eacl/table_test.go index 4ec110f..80dd8d4 100644 --- a/eacl/table_test.go +++ b/eacl/table_test.go @@ -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()) }) } diff --git a/eacl/target.go b/eacl/target.go index 5e34950..9de35b1 100644 --- a/eacl/target.go +++ b/eacl/target.go @@ -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 } diff --git a/eacl/target_test.go b/eacl/target_test.go index e226194..ccd6edb 100644 --- a/eacl/target_test.go +++ b/eacl/target_test.go @@ -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()) }) } diff --git a/eacl/types.go b/eacl/types.go index 9b79e79..b191bdb 100644 --- a/eacl/types.go +++ b/eacl/types.go @@ -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 diff --git a/eacl/validator.go b/eacl/validator.go index dd313bb..a5a77c7 100644 --- a/eacl/validator.go +++ b/eacl/validator.go @@ -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() }, } diff --git a/eacl/validator_test.go b/eacl/validator_test.go index 3b8d9f1..e0d75e3 100644 --- a/eacl/validator_test.go +++ b/eacl/validator_test.go @@ -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) diff --git a/go.mod b/go.mod index fc96fa4..0e407b6 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index 11f92d0..c38599c 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/netmap/aggregator.go b/netmap/aggregator.go index c018e6b..8784a24 100644 --- a/netmap/aggregator.go +++ b/netmap/aggregator.go @@ -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())) } } diff --git a/netmap/context.go b/netmap/context.go index 00942e5..33df68d 100644 --- a/netmap/context.go +++ b/netmap/context.go @@ -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), diff --git a/netmap/filter.go b/netmap/filter.go index 71e101d..60aa5e2 100644 --- a/netmap/filter.go +++ b/netmap/filter.go @@ -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 diff --git a/netmap/filter_test.go b/netmap/filter_test.go index 2b88b3c..11c3918 100644 --- a/netmap/filter_test.go +++ b/netmap/filter_test.go @@ -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)) } diff --git a/netmap/helper_test.go b/netmap/helper_test.go index 3775f18..5442180 100644 --- a/netmap/helper_test.go +++ b/netmap/helper_test.go @@ -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]) } diff --git a/netmap/netmap.go b/netmap/netmap.go index 7da41a8..1dced2d 100644 --- a/netmap/netmap.go +++ b/netmap/netmap.go @@ -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 } diff --git a/netmap/netmap_test.go b/netmap/netmap_test.go index 7c286a4..33ddf66 100644 --- a/netmap/netmap_test.go +++ b/netmap/netmap_test.go @@ -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()) } diff --git a/netmap/network_info.go b/netmap/network_info.go index 186d433..04446cd 100644 --- a/netmap/network_info.go +++ b/netmap/network_info.go @@ -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) } diff --git a/netmap/network_info_test.go b/netmap/network_info_test.go index 54b1b30..4050372 100644 --- a/netmap/network_info_test.go +++ b/netmap/network_info_test.go @@ -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()) diff --git a/netmap/node_info.go b/netmap/node_info.go index 8f323f7..d4a9f20 100644 --- a/netmap/node_info.go +++ b/netmap/node_info.go @@ -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 } diff --git a/netmap/node_info_test.go b/netmap/node_info_test.go index 1d1c018..2285b09 100644 --- a/netmap/node_info_test.go +++ b/netmap/node_info_test.go @@ -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() }) diff --git a/netmap/policy.go b/netmap/policy.go index 323050e..c27d782 100644 --- a/netmap/policy.go +++ b/netmap/policy.go @@ -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)) diff --git a/netmap/policy_test.go b/netmap/policy_test.go index 98ce5f2..5b435ef 100644 --- a/netmap/policy_test.go +++ b/netmap/policy_test.go @@ -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)) }) } diff --git a/netmap/selector.go b/netmap/selector.go index d8c767a..e0ca6d3 100644 --- a/netmap/selector.go +++ b/netmap/selector.go @@ -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]}}) diff --git a/netmap/selector_test.go b/netmap/selector_test.go index a80d922..2df55da 100644 --- a/netmap/selector_test.go +++ b/netmap/selector_test.go @@ -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()) diff --git a/netmap/test/generate.go b/netmap/test/generate.go index 3f5f26b..8e6ae61 100644 --- a/netmap/test/generate.go +++ b/netmap/test/generate.go @@ -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) diff --git a/object/attribute.go b/object/attribute.go index e4c7f60..802a2be 100644 --- a/object/attribute.go +++ b/object/attribute.go @@ -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) } diff --git a/object/attribute_test.go b/object/attribute_test.go index eafc312..63288dd 100644 --- a/object/attribute_test.go +++ b/object/attribute_test.go @@ -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() diff --git a/object/fmt.go b/object/fmt.go index 5e6386d..397e68f 100644 --- a/object/fmt.go +++ b/object/fmt.go @@ -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. diff --git a/object/fmt_test.go b/object/fmt_test.go index b747080..8e2323e 100644 --- a/object/fmt_test.go +++ b/object/fmt_test.go @@ -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]-- }, }, } diff --git a/object/id/address.go b/object/id/address.go index 6d5f12a..028ad6c 100644 --- a/object/id/address.go +++ b/object/id/address.go @@ -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 } diff --git a/object/id/address_test.go b/object/id/address_test.go index 5ae91ca..ad6cef8 100644 --- a/object/id/address_test.go +++ b/object/id/address_test.go @@ -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) { diff --git a/object/id/id.go b/object/id/id.go index 5ba0c6d..94627a2 100644 --- a/object/id/id.go +++ b/object/id/id.go @@ -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 } diff --git a/object/id/id_test.go b/object/id/id_test.go index bdc0b4d..c7b6414 100644 --- a/object/id/id_test.go +++ b/object/id/id_test.go @@ -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)) }) } diff --git a/object/lock.go b/object/lock.go index dd08eba..202b803 100644 --- a/object/lock.go +++ b/object/lock.go @@ -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) } diff --git a/object/lock_test.go b/object/lock_test.go index c1c5f97..3e6e287 100644 --- a/object/lock_test.go +++ b/object/lock_test.go @@ -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)) } diff --git a/object/object.go b/object/object.go index b21cd69..e3bd65a 100644 --- a/object/object.go +++ b/object/object.go @@ -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) } diff --git a/object/object_test.go b/object/object_test.go index 61b5521..0e930b7 100644 --- a/object/object_test.go +++ b/object/object_test.go @@ -10,11 +10,11 @@ import ( ) func TestInitCreation(t *testing.T) { - var o object.Object + o := object.New() cnr := cidtest.ID() own := *usertest.ID() - object.InitCreation(&o, object.RequiredFields{ + object.InitCreation(o, object.RequiredFields{ Container: cnr, Owner: own, }) diff --git a/object/range.go b/object/range.go index 87ad3b7..13468f2 100644 --- a/object/range.go +++ b/object/range.go @@ -1,17 +1,27 @@ package object import ( - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" + v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object/grpc" + "google.golang.org/protobuf/proto" ) // Range represents v2-compatible object payload range. -type Range object.Range +type Range struct { + objectrange *v2object.Range +} // NewRangeFromV2 wraps v2 Range message to Range. // -// Nil object.Range converts to nil. -func NewRangeFromV2(rV2 *object.Range) *Range { - return (*Range)(rV2) +// Nil v2object.Range converts to nil. +func NewRangeFromV2(rV2 *v2object.Range) *Range { + if rV2 == nil { + return nil + } + var objectrange v2object.Range + proto.Merge(&objectrange, rV2) + return &Range{ + objectrange: &objectrange, + } } // NewRange creates and initializes blank Range. @@ -20,32 +30,41 @@ func NewRangeFromV2(rV2 *object.Range) *Range { // - offset: 0; // - length: 0. func NewRange() *Range { - return NewRangeFromV2(new(object.Range)) + return NewRangeFromV2(new(v2object.Range)) } // ToV2 converts Range to v2 Range message. // // Nil Range converts to nil. -func (r *Range) ToV2() *object.Range { - return (*object.Range)(r) +func (r *Range) ToV2() *v2object.Range { + if r == nil { + return nil + } + return r.objectrange } // GetLength returns payload range size. func (r *Range) GetLength() uint64 { - return (*object.Range)(r).GetLength() + if r == nil { + return 0 + } + return r.objectrange.GetLength() } // SetLength sets payload range size. func (r *Range) SetLength(v uint64) { - (*object.Range)(r).SetLength(v) + r.objectrange.SetLength(v) } // GetOffset sets payload range offset from start. func (r *Range) GetOffset() uint64 { - return (*object.Range)(r).GetOffset() + if r == nil { + return 0 + } + return r.objectrange.GetOffset() } // SetOffset gets payload range offset from start. func (r *Range) SetOffset(v uint64) { - (*object.Range)(r).SetOffset(v) + r.objectrange.SetOffset(v) } diff --git a/object/range_test.go b/object/range_test.go index c8208d8..b3b1700 100644 --- a/object/range_test.go +++ b/object/range_test.go @@ -3,7 +3,7 @@ package object import ( "testing" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" + v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object/grpc" "github.com/stretchr/testify/require" ) @@ -27,7 +27,7 @@ func TestRange_SetLength(t *testing.T) { func TestNewRangeFromV2(t *testing.T) { t.Run("from nil", func(t *testing.T) { - var x *object.Range + var x *v2object.Range require.Nil(t, NewRangeFromV2(x)) }) diff --git a/object/raw.go b/object/raw.go index 5c91f1d..7657bb4 100644 --- a/object/raw.go +++ b/object/raw.go @@ -1,7 +1,7 @@ package object import ( - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" + v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object/grpc" ) // RawObject represents v2-compatible FrostFS object that provides @@ -14,7 +14,7 @@ type RawObject = Object // NewRawFromV2 wraps v2 Object message to Object. // // Deprecated: (v1.0.0) use NewFromV2 function instead. -func NewRawFromV2(oV2 *object.Object) *Object { +func NewRawFromV2(oV2 *v2object.Object) *Object { return NewFromV2(oV2) } diff --git a/object/raw_test.go b/object/raw_test.go index 52ac9de..a296d8a 100644 --- a/object/raw_test.go +++ b/object/raw_test.go @@ -5,13 +5,14 @@ import ( "crypto/sha256" "testing" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" + v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object/grpc" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/checksum" cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" sessiontest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session/test" usertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user/test" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version" + "github.com/golang/protobuf/proto" "github.com/stretchr/testify/require" ) @@ -62,13 +63,14 @@ func TestObject_SetPayload(t *testing.T) { func TestObject_SetVersion(t *testing.T) { obj := New() - var ver version.Version + ver := version.NewVersion() ver.SetMajor(1) ver.SetMinor(2) - obj.SetVersion(&ver) + obj.SetVersion(ver) - require.Equal(t, ver, *obj.Version()) + require.Equal(t, ver.GetMinor(), obj.Version().GetMinor()) + require.Equal(t, ver.GetMajor(), obj.Version().GetMajor()) } func TestObject_SetPayloadSize(t *testing.T) { @@ -113,7 +115,7 @@ func TestObject_SetCreationEpoch(t *testing.T) { func TestObject_SetPayloadChecksum(t *testing.T) { obj := New() - var cs checksum.Checksum + cs := checksum.NewChecksum() cs.SetSHA256(randSHA256Checksum(t)) obj.SetPayloadChecksum(cs) @@ -126,7 +128,7 @@ func TestObject_SetPayloadChecksum(t *testing.T) { func TestObject_SetPayloadHomomorphicHash(t *testing.T) { obj := New() - var cs checksum.Checksum + cs := checksum.NewChecksum() cs.SetTillichZemor(randTZChecksum(t)) obj.SetPayloadHomomorphicHash(cs) @@ -198,11 +200,11 @@ func TestObject_SetParent(t *testing.T) { obj.SetParent(par) - require.Equal(t, par, obj.Parent()) + require.True(t, proto.Equal(par.object, obj.Parent().object)) } func TestObject_ToV2(t *testing.T) { - objV2 := new(object.Object) + objV2 := new(v2object.Object) objV2.SetPayload([]byte{1, 2, 3}) obj := NewFromV2(objV2) @@ -217,7 +219,7 @@ func TestObject_SetSessionToken(t *testing.T) { obj.SetSessionToken(tok) - require.Equal(t, tok, obj.SessionToken()) + require.Equal(t, tok.Marshal(), obj.SessionToken().Marshal()) } func TestObject_CutPayload(t *testing.T) { @@ -238,13 +240,14 @@ func TestObject_CutPayload(t *testing.T) { o1.SetPayloadSize(sz) require.Equal(t, sz, o1.PayloadSize()) - require.Equal(t, sz, o2.PayloadSize()) + require.NotEqual(t, sz, o2.PayloadSize()) p2 := []byte{4, 5, 6} o2.SetPayload(p2) require.Equal(t, p2, o2.Payload()) require.Equal(t, p1, o1.Payload()) + require.NotEqual(t, o1.Payload(), o2.Payload()) } func TestObject_SetParentID(t *testing.T) { @@ -293,7 +296,7 @@ func TestObjectEncoding(t *testing.T) { o2 := New() require.NoError(t, o2.Unmarshal(data)) - require.Equal(t, o, o2) + require.True(t, proto.Equal(o.object, o2.object)) }) t.Run("json", func(t *testing.T) { @@ -303,6 +306,6 @@ func TestObjectEncoding(t *testing.T) { o2 := New() require.NoError(t, o2.UnmarshalJSON(data)) - require.Equal(t, o, o2) + require.True(t, proto.Equal(o.object, o2.object)) }) } diff --git a/object/search.go b/object/search.go index f3df671..584ed8f 100644 --- a/object/search.go +++ b/object/search.go @@ -4,10 +4,12 @@ import ( "encoding/json" "strconv" - v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" + "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" + v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object/grpc" 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/user" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/util/slices" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version" ) @@ -25,27 +27,27 @@ const ( func (m SearchMatchType) ToV2() v2object.MatchType { switch m { case MatchStringEqual: - return v2object.MatchStringEqual + return v2object.MatchType_STRING_EQUAL case MatchStringNotEqual: - return v2object.MatchStringNotEqual + return v2object.MatchType_STRING_NOT_EQUAL case MatchNotPresent: - return v2object.MatchNotPresent + return v2object.MatchType_NOT_PRESENT case MatchCommonPrefix: - return v2object.MatchCommonPrefix + return v2object.MatchType_COMMON_PREFIX default: - return v2object.MatchUnknown + return v2object.MatchType_MATCH_TYPE_UNSPECIFIED } } func SearchMatchFromV2(t v2object.MatchType) (m SearchMatchType) { switch t { - case v2object.MatchStringEqual: + case v2object.MatchType_STRING_EQUAL: m = MatchStringEqual - case v2object.MatchStringNotEqual: + case v2object.MatchType_STRING_NOT_EQUAL: m = MatchStringNotEqual - case v2object.MatchNotPresent: + case v2object.MatchType_NOT_PRESENT: m = MatchNotPresent - case v2object.MatchCommonPrefix: + case v2object.MatchType_COMMON_PREFIX: m = MatchCommonPrefix default: m = MatchUnknown @@ -127,31 +129,31 @@ func (k filterKey) String() string { default: return k.str case fKeyVersion: - return v2object.FilterHeaderVersion + return object.FilterHeaderVersion case fKeyObjectID: - return v2object.FilterHeaderObjectID + return object.FilterHeaderObjectID case fKeyContainerID: - return v2object.FilterHeaderContainerID + return object.FilterHeaderContainerID case fKeyOwnerID: - return v2object.FilterHeaderOwnerID + return object.FilterHeaderOwnerID case fKeyCreationEpoch: - return v2object.FilterHeaderCreationEpoch + return object.FilterHeaderCreationEpoch case fKeyPayloadLength: - return v2object.FilterHeaderPayloadLength + return object.FilterHeaderPayloadLength case fKeyPayloadHash: - return v2object.FilterHeaderPayloadHash + return object.FilterHeaderPayloadHash case fKeyType: - return v2object.FilterHeaderObjectType + return object.FilterHeaderObjectType case fKeyHomomorphicHash: - return v2object.FilterHeaderHomomorphicHash + return object.FilterHeaderHomomorphicHash case fKeyParent: - return v2object.FilterHeaderParent + return object.FilterHeaderParent case fKeySplitID: - return v2object.FilterHeaderSplitID + return object.FilterHeaderSplitID case fKeyPropRoot: - return v2object.FilterPropertyRoot + return object.FilterPropertyRoot case fKeyPropPhy: - return v2object.FilterPropertyPhy + return object.FilterPropertyPhy } } @@ -175,7 +177,7 @@ func NewSearchFilters() SearchFilters { return SearchFilters{} } -func NewSearchFiltersFromV2(v2 []v2object.SearchFilter) SearchFilters { +func NewSearchFiltersFromV2(v2 []*v2object.SearchRequest_Body_Filter) SearchFilters { filters := make(SearchFilters, 0, len(v2)) for i := range v2 { @@ -232,12 +234,11 @@ func (f *SearchFilters) AddObjectOwnerIDFilter(m SearchMatchType, id user.ID) { } func (f *SearchFilters) AddNotificationEpochFilter(epoch uint64) { - f.addFilter(MatchStringEqual, 0, v2object.SysAttributeTickEpoch, staticStringer(strconv.FormatUint(epoch, 10))) + f.addFilter(MatchStringEqual, 0, object.SysAttributeTickEpoch, staticStringer(strconv.FormatUint(epoch, 10))) } -func (f SearchFilters) ToV2() []v2object.SearchFilter { - result := make([]v2object.SearchFilter, len(f)) - +func (f SearchFilters) ToV2() []*v2object.SearchRequest_Body_Filter { + result := slices.MakePreallocPointerSlice[v2object.SearchRequest_Body_Filter](len(f)) for i := range f { result[i].SetKey(f[i].header.String()) result[i].SetValue(f[i].value.EncodeToString()) @@ -289,7 +290,7 @@ func (f *SearchFilters) MarshalJSON() ([]byte, error) { // UnmarshalJSON decodes SearchFilters from protobuf JSON format. func (f *SearchFilters) UnmarshalJSON(data []byte) error { - var fsV2 []v2object.SearchFilter + var fsV2 []*v2object.SearchRequest_Body_Filter if err := json.Unmarshal(data, &fsV2); err != nil { return err diff --git a/object/search_test.go b/object/search_test.go index d0f36de..2a41488 100644 --- a/object/search_test.go +++ b/object/search_test.go @@ -5,18 +5,19 @@ import ( "math/rand" "testing" - v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" + objectapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" + v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object/grpc" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" "github.com/stretchr/testify/require" ) var eqV2Matches = map[object.SearchMatchType]v2object.MatchType{ - object.MatchUnknown: v2object.MatchUnknown, - object.MatchStringEqual: v2object.MatchStringEqual, - object.MatchStringNotEqual: v2object.MatchStringNotEqual, - object.MatchNotPresent: v2object.MatchNotPresent, - object.MatchCommonPrefix: v2object.MatchCommonPrefix, + object.MatchUnknown: v2object.MatchType_MATCH_TYPE_UNSPECIFIED, + object.MatchStringEqual: v2object.MatchType_STRING_EQUAL, + object.MatchStringNotEqual: v2object.MatchType_STRING_NOT_EQUAL, + object.MatchNotPresent: v2object.MatchType_NOT_PRESENT, + object.MatchCommonPrefix: v2object.MatchType_COMMON_PREFIX, } func TestMatch(t *testing.T) { @@ -36,7 +37,7 @@ func TestMatch(t *testing.T) { unknownMatchType++ - require.Equal(t, unknownMatchType.ToV2(), v2object.MatchUnknown) + require.Equal(t, unknownMatchType.ToV2(), v2object.MatchType_MATCH_TYPE_UNSPECIFIED) var unknownMatchTypeV2 v2object.MatchType @@ -82,7 +83,7 @@ func TestSearchFilters_AddRootFilter(t *testing.T) { f := (*fs)[0] require.Equal(t, object.MatchUnknown, f.Operation()) - require.Equal(t, v2object.FilterPropertyRoot, f.Header()) + require.Equal(t, objectapi.FilterPropertyRoot, f.Header()) require.Equal(t, "", f.Value()) } @@ -96,7 +97,7 @@ func TestSearchFilters_AddPhyFilter(t *testing.T) { f := (*fs)[0] require.Equal(t, object.MatchUnknown, f.Operation()) - require.Equal(t, v2object.FilterPropertyPhy, f.Header()) + require.Equal(t, objectapi.FilterPropertyPhy, f.Header()) require.Equal(t, "", f.Value()) } @@ -121,9 +122,9 @@ func TestSearchFilters_AddParentIDFilter(t *testing.T) { require.Len(t, fsV2, 1) - require.Equal(t, v2object.FilterHeaderParent, fsV2[0].GetKey()) + require.Equal(t, objectapi.FilterHeaderParent, fsV2[0].GetKey()) require.Equal(t, par.EncodeToString(), fsV2[0].GetValue()) - require.Equal(t, v2object.MatchStringEqual, fsV2[0].GetMatchType()) + require.Equal(t, v2object.MatchType_STRING_EQUAL, fsV2[0].GetMatchType()) } func TestSearchFilters_AddObjectIDFilter(t *testing.T) { @@ -137,9 +138,9 @@ func TestSearchFilters_AddObjectIDFilter(t *testing.T) { require.Len(t, fsV2, 1) - require.Equal(t, v2object.FilterHeaderObjectID, fsV2[0].GetKey()) + require.Equal(t, objectapi.FilterHeaderObjectID, fsV2[0].GetKey()) require.Equal(t, id.EncodeToString(), fsV2[0].GetValue()) - require.Equal(t, v2object.MatchStringEqual, fsV2[0].GetMatchType()) + require.Equal(t, v2object.MatchType_STRING_EQUAL, fsV2[0].GetMatchType()) }) } @@ -154,9 +155,9 @@ func TestSearchFilters_AddSplitIDFilter(t *testing.T) { require.Len(t, fsV2, 1) - require.Equal(t, v2object.FilterHeaderSplitID, fsV2[0].GetKey()) + require.Equal(t, objectapi.FilterHeaderSplitID, fsV2[0].GetKey()) require.Equal(t, id.String(), fsV2[0].GetValue()) - require.Equal(t, v2object.MatchStringEqual, fsV2[0].GetMatchType()) + require.Equal(t, v2object.MatchType_STRING_EQUAL, fsV2[0].GetMatchType()) }) } @@ -171,9 +172,9 @@ func TestSearchFilters_AddTypeFilter(t *testing.T) { require.Len(t, fsV2, 1) - require.Equal(t, v2object.FilterHeaderObjectType, fsV2[0].GetKey()) + require.Equal(t, objectapi.FilterHeaderObjectType, fsV2[0].GetKey()) require.Equal(t, typ.String(), fsV2[0].GetValue()) - require.Equal(t, v2object.MatchStringEqual, fsV2[0].GetMatchType()) + require.Equal(t, v2object.MatchType_STRING_EQUAL, fsV2[0].GetMatchType()) }) } diff --git a/object/splitinfo.go b/object/splitinfo.go index c38b2a4..0281a6a 100644 --- a/object/splitinfo.go +++ b/object/splitinfo.go @@ -4,18 +4,30 @@ import ( "errors" "fmt" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" + object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object/grpc" + v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object/grpc" + refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) -type SplitInfo object.SplitInfo +type SplitInfo struct { + splitInfo *v2object.SplitInfo +} // NewSplitInfoFromV2 wraps v2 SplitInfo message to SplitInfo. // // Nil object.SplitInfo converts to nil. -func NewSplitInfoFromV2(v2 *object.SplitInfo) *SplitInfo { - return (*SplitInfo)(v2) +func NewSplitInfoFromV2(v2 *v2object.SplitInfo) *SplitInfo { + if v2 == nil { + return nil + } + si := new(v2object.SplitInfo) + proto.Merge(si, v2) + return &SplitInfo{ + splitInfo: si, + } } // NewSplitInfo creates and initializes blank SplitInfo. @@ -25,31 +37,36 @@ func NewSplitInfoFromV2(v2 *object.SplitInfo) *SplitInfo { // - lastPart nil; // - link: nil. func NewSplitInfo() *SplitInfo { - return NewSplitInfoFromV2(new(object.SplitInfo)) + return NewSplitInfoFromV2(new(v2object.SplitInfo)) } // ToV2 converts SplitInfo to v2 SplitInfo message. // // Nil SplitInfo converts to nil. -func (s *SplitInfo) ToV2() *object.SplitInfo { - return (*object.SplitInfo)(s) +func (s *SplitInfo) ToV2() *v2object.SplitInfo { + if s == nil { + return nil + } + return s.splitInfo } func (s *SplitInfo) SplitID() *SplitID { - return NewSplitIDFromV2( - (*object.SplitInfo)(s).GetSplitID()) + if s == nil { + return nil + } + return NewSplitIDFromV2(s.splitInfo.GetSplitId()) } func (s *SplitInfo) SetSplitID(v *SplitID) { - (*object.SplitInfo)(s).SetSplitID(v.ToV2()) + s.splitInfo.SetSplitId(v.ToV2()) } func (s SplitInfo) LastPart() (v oid.ID, isSet bool) { - v2 := (object.SplitInfo)(s) + v2 := s.splitInfo lpV2 := v2.GetLastPart() if lpV2 != nil { - _ = v.ReadFromV2(*lpV2) + _ = v.ReadFromV2(lpV2) isSet = true } @@ -59,16 +76,15 @@ func (s SplitInfo) LastPart() (v oid.ID, isSet bool) { func (s *SplitInfo) SetLastPart(v oid.ID) { var idV2 refs.ObjectID v.WriteToV2(&idV2) - - (*object.SplitInfo)(s).SetLastPart(&idV2) + s.splitInfo.SetLastPart(&idV2) } func (s SplitInfo) Link() (v oid.ID, isSet bool) { - v2 := (object.SplitInfo)(s) + v2 := s.splitInfo linkV2 := v2.GetLink() if linkV2 != nil { - _ = v.ReadFromV2(*linkV2) + _ = v.ReadFromV2(linkV2) isSet = true } @@ -78,36 +94,39 @@ func (s SplitInfo) Link() (v oid.ID, isSet bool) { func (s *SplitInfo) SetLink(v oid.ID) { var idV2 refs.ObjectID v.WriteToV2(&idV2) - - (*object.SplitInfo)(s).SetLink(&idV2) + s.splitInfo.SetLink(&idV2) } func (s *SplitInfo) Marshal() ([]byte, error) { - return (*object.SplitInfo)(s).StableMarshal(nil), nil + return s.splitInfo.StableMarshal(nil), nil } func (s *SplitInfo) Unmarshal(data []byte) error { - err := (*object.SplitInfo)(s).Unmarshal(data) + err := proto.Unmarshal(data, s.splitInfo) if err != nil { return err } - return formatCheckSI((*object.SplitInfo)(s)) + return formatCheckSI(s.splitInfo) } // MarshalJSON implements json.Marshaler. func (s *SplitInfo) MarshalJSON() ([]byte, error) { - return (*object.SplitInfo)(s).MarshalJSON() + return protojson.MarshalOptions{ + EmitUnpopulated: true, + }.Marshal( + s.splitInfo, + ) } // UnmarshalJSON implements json.Unmarshaler. func (s *SplitInfo) UnmarshalJSON(data []byte) error { - err := (*object.SplitInfo)(s).UnmarshalJSON(data) + err := protojson.Unmarshal(data, s.splitInfo) if err != nil { return err } - return formatCheckSI((*object.SplitInfo)(s)) + return formatCheckSI(s.splitInfo) } var errSplitInfoMissingFields = errors.New("neither link object ID nor last part object ID is set") @@ -122,14 +141,14 @@ func formatCheckSI(v2 *object.SplitInfo) error { var oID oid.ID if link != nil { - err := oID.ReadFromV2(*link) + err := oID.ReadFromV2(link) if err != nil { return fmt.Errorf("could not convert link object ID: %w", err) } } if lastPart != nil { - err := oID.ReadFromV2(*lastPart) + err := oID.ReadFromV2(lastPart) if err != nil { return fmt.Errorf("could not convert last part object ID: %w", err) } diff --git a/object/splitinfo_test.go b/object/splitinfo_test.go index ba3a54f..a797fae 100644 --- a/object/splitinfo_test.go +++ b/object/splitinfo_test.go @@ -5,9 +5,10 @@ import ( "encoding/json" "testing" - objv2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" + objv2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object/grpc" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" + "github.com/golang/protobuf/proto" "github.com/stretchr/testify/require" ) @@ -36,7 +37,7 @@ func TestSplitInfoMarshal(t *testing.T) { v2 := s.ToV2() newS := object.NewSplitInfoFromV2(v2) - require.Equal(t, s, newS) + require.True(t, proto.Equal(s.ToV2(), newS.ToV2())) } testMarshal := func(t *testing.T, s *object.SplitInfo) { data, err := s.Marshal() @@ -46,7 +47,7 @@ func TestSplitInfoMarshal(t *testing.T) { err = newS.Unmarshal(data) require.NoError(t, err) - require.Equal(t, s, newS) + require.True(t, proto.Equal(s.ToV2(), newS.ToV2())) } t.Run("good, both fields are set", func(t *testing.T) { @@ -124,7 +125,7 @@ func TestNewSplitInfo(t *testing.T) { // convert to v2 message siV2 := si.ToV2() - require.Nil(t, siV2.GetSplitID()) + require.Nil(t, siV2.GetSplitId()) require.Nil(t, siV2.GetLastPart()) require.Nil(t, siV2.GetLink()) }) diff --git a/object/test/generate.go b/object/test/generate.go index 526e757..ae7209a 100644 --- a/object/test/generate.go +++ b/object/test/generate.go @@ -51,7 +51,7 @@ func generate(withParent bool) *object.Object { x.SetOwnerID(usertest.ID()) x.SetContainerID(cidtest.ID()) x.SetType(object.TypeTombstone) - x.SetVersion(&ver) + x.SetVersion(ver) x.SetPayloadSize(111) x.SetCreationEpoch(222) x.SetPreviousID(oidtest.ID()) @@ -114,8 +114,8 @@ func SearchFilters() object.SearchFilters { // Lock returns random object.Lock. func Lock() *object.Lock { - var l object.Lock + l := object.NewLock() l.WriteMembers([]oid.ID{oidtest.ID(), oidtest.ID()}) - return &l + return l } diff --git a/object/tombstone.go b/object/tombstone.go index e332630..931feaf 100644 --- a/object/tombstone.go +++ b/object/tombstone.go @@ -1,19 +1,30 @@ package object import ( - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/tombstone" + refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc" + tombgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/tombstone/grpc" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) // Tombstone represents v2-compatible tombstone structure. -type Tombstone tombstone.Tombstone +type Tombstone struct { + tombstone *tombgrpc.Tombstone +} // NewTombstoneFromV2 wraps v2 Tombstone message to Tombstone. // // Nil tombstone.Tombstone converts to nil. -func NewTombstoneFromV2(tV2 *tombstone.Tombstone) *Tombstone { - return (*Tombstone)(tV2) +func NewTombstoneFromV2(tV2 *tombgrpc.Tombstone) *Tombstone { + if tV2 == nil { + return nil + } + ts := new(tombgrpc.Tombstone) + proto.Merge(ts, tV2) + return &Tombstone{ + tombstone: ts, + } } // NewTombstone creates and initializes blank Tombstone. @@ -23,14 +34,17 @@ func NewTombstoneFromV2(tV2 *tombstone.Tombstone) *Tombstone { // - splitID: nil; // - members: nil. func NewTombstone() *Tombstone { - return NewTombstoneFromV2(new(tombstone.Tombstone)) + return NewTombstoneFromV2(new(tombgrpc.Tombstone)) } // ToV2 converts Tombstone to v2 Tombstone message. // // Nil Tombstone converts to nil. -func (t *Tombstone) ToV2() *tombstone.Tombstone { - return (*tombstone.Tombstone)(t) +func (t *Tombstone) ToV2() *tombgrpc.Tombstone { + if t == nil { + return nil + } + return t.tombstone } // ExpirationEpoch returns the last FrostFS epoch @@ -38,7 +52,7 @@ func (t *Tombstone) ToV2() *tombstone.Tombstone { // // See also SetExpirationEpoch. func (t *Tombstone) ExpirationEpoch() uint64 { - return (*tombstone.Tombstone)(t).GetExpirationEpoch() + return t.tombstone.GetExpirationEpoch() } // SetExpirationEpoch sets the last FrostFS epoch @@ -46,23 +60,23 @@ func (t *Tombstone) ExpirationEpoch() uint64 { // // See also ExpirationEpoch. func (t *Tombstone) SetExpirationEpoch(v uint64) { - (*tombstone.Tombstone)(t).SetExpirationEpoch(v) + t.tombstone.SetExpirationEpoch(v) } // SplitID returns identifier of object split hierarchy. func (t *Tombstone) SplitID() *SplitID { return NewSplitIDFromV2( - (*tombstone.Tombstone)(t).GetSplitID()) + t.tombstone.GetSplitId()) } // SetSplitID sets identifier of object split hierarchy. func (t *Tombstone) SetSplitID(v *SplitID) { - (*tombstone.Tombstone)(t).SetSplitID(v.ToV2()) + t.tombstone.SetSplitId(v.ToV2()) } // Members returns list of objects to be deleted. func (t *Tombstone) Members() []oid.ID { - v2 := (*tombstone.Tombstone)(t) + v2 := t.tombstone msV2 := v2.GetMembers() if msV2 == nil { @@ -84,45 +98,50 @@ func (t *Tombstone) Members() []oid.ID { // SetMembers sets list of objects to be deleted. func (t *Tombstone) SetMembers(v []oid.ID) { - var ms []refs.ObjectID + var ms []*refsgrpc.ObjectID if v != nil { - ms = (*tombstone.Tombstone)(t). - GetMembers() + ms = t.tombstone.GetMembers() if ln := len(v); cap(ms) >= ln { ms = ms[:0] } else { - ms = make([]refs.ObjectID, 0, ln) + ms = make([]*refsgrpc.ObjectID, 0, ln) } - var idV2 refs.ObjectID - for i := range v { + var idV2 refsgrpc.ObjectID v[i].WriteToV2(&idV2) - ms = append(ms, idV2) + ms = append(ms, &idV2) } } - (*tombstone.Tombstone)(t).SetMembers(ms) + if t.tombstone == nil { + t.tombstone = new(tombgrpc.Tombstone) + } + t.tombstone.SetMembers(ms) } // Marshal marshals Tombstone into a protobuf binary form. func (t *Tombstone) Marshal() ([]byte, error) { - return (*tombstone.Tombstone)(t).StableMarshal(nil), nil + return t.tombstone.StableMarshal(nil), nil } // Unmarshal unmarshals protobuf binary representation of Tombstone. func (t *Tombstone) Unmarshal(data []byte) error { - return (*tombstone.Tombstone)(t).Unmarshal(data) + return proto.Unmarshal(data, t.tombstone) } // MarshalJSON encodes Tombstone to protobuf JSON format. func (t *Tombstone) MarshalJSON() ([]byte, error) { - return (*tombstone.Tombstone)(t).MarshalJSON() + return protojson.MarshalOptions{ + EmitUnpopulated: true, + }.Marshal( + t.tombstone, + ) } // UnmarshalJSON decodes Tombstone from protobuf JSON format. func (t *Tombstone) UnmarshalJSON(data []byte) error { - return (*tombstone.Tombstone)(t).UnmarshalJSON(data) + return protojson.Unmarshal(data, t.tombstone) } diff --git a/object/tombstone_test.go b/object/tombstone_test.go index cd74e45..517af30 100644 --- a/object/tombstone_test.go +++ b/object/tombstone_test.go @@ -5,8 +5,9 @@ import ( "math/rand" "testing" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/tombstone" + tombgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/tombstone/grpc" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" + "github.com/golang/protobuf/proto" "github.com/stretchr/testify/require" ) @@ -54,7 +55,7 @@ func TestTombstoneEncoding(t *testing.T) { ts2 := NewTombstone() require.NoError(t, ts2.Unmarshal(data)) - require.Equal(t, ts, ts2) + require.True(t, proto.Equal(ts.ToV2(), ts2.ToV2())) }) t.Run("json", func(t *testing.T) { @@ -64,13 +65,13 @@ func TestTombstoneEncoding(t *testing.T) { ts2 := NewTombstone() require.NoError(t, ts2.UnmarshalJSON(data)) - require.Equal(t, ts, ts2) + require.True(t, proto.Equal(ts.ToV2(), ts2.ToV2())) }) } func TestNewTombstoneFromV2(t *testing.T) { t.Run("from nil", func(t *testing.T) { - var x *tombstone.Tombstone + var x *tombgrpc.Tombstone require.Nil(t, NewTombstoneFromV2(x)) }) @@ -88,7 +89,7 @@ func TestNewTombstone(t *testing.T) { // convert to v2 message tsV2 := ts.ToV2() - require.Nil(t, tsV2.GetSplitID()) + require.Nil(t, tsV2.GetSplitId()) require.Nil(t, tsV2.GetMembers()) require.Zero(t, tsV2.GetExpirationEpoch()) }) diff --git a/object/transformer/channel_test.go b/object/transformer/channel_test.go index 6b17bd5..72c164b 100644 --- a/object/transformer/channel_test.go +++ b/object/transformer/channel_test.go @@ -26,7 +26,7 @@ func TestChannelTarget(t *testing.T) { hdr := objectSDK.New() hdr.SetContainerID(cnr) hdr.SetType(objectSDK.TypeRegular) - hdr.SetVersion(&ver) + hdr.SetVersion(ver) payload := make([]byte, maxSize*2+maxSize/2) _, _ = rand.Read(payload) diff --git a/object/transformer/hasher.go b/object/transformer/hasher.go index 25ae3c8..92e0fba 100644 --- a/object/transformer/hasher.go +++ b/object/transformer/hasher.go @@ -20,7 +20,7 @@ func (h payloadChecksumHasher) writeChecksum(obj *objectSDK.Object) { csSHA := [sha256.Size]byte{} h.hasher.Sum(csSHA[:0]) - var cs checksum.Checksum + cs := checksum.NewChecksum() cs.SetSHA256(csSHA) obj.SetPayloadChecksum(cs) @@ -28,7 +28,7 @@ func (h payloadChecksumHasher) writeChecksum(obj *objectSDK.Object) { csTZ := [tz.Size]byte{} h.hasher.Sum(csTZ[:0]) - var cs checksum.Checksum + cs := checksum.NewChecksum() cs.SetTillichZemor(csTZ) obj.SetPayloadHomomorphicHash(cs) diff --git a/object/transformer/transformer.go b/object/transformer/transformer.go index a175662..b1606de 100644 --- a/object/transformer/transformer.go +++ b/object/transformer/transformer.go @@ -87,7 +87,7 @@ func (s *payloadSizeLimiter) initialize() { s.parent.ResetRelations() s.parent.SetSignature(nil) s.parent.SetAttributes(s.parAttrs...) - s.parent.SetVersion(&ver) + s.parent.SetVersion(ver) s.parentHashers = append(s.parentHashers[:0], s.currentHashers...) } @@ -188,7 +188,7 @@ func (s *payloadSizeLimiter) fillHeader() (*AccessIdentifiers, error) { curEpoch := s.NetworkState.CurrentEpoch() ver := version.Current() - s.current.SetVersion(&ver) + s.current.SetVersion(ver) s.current.SetPayloadSize(s.writtenCurrent) s.current.SetSessionToken(s.SessionToken) s.current.SetCreationEpoch(curEpoch) diff --git a/object/transformer/transformer_test.go b/object/transformer/transformer_test.go index 11a6843..1e945ac 100644 --- a/object/transformer/transformer_test.go +++ b/object/transformer/transformer_test.go @@ -95,7 +95,7 @@ func newObject(cnr cid.ID) *objectSDK.Object { hdr := objectSDK.New() hdr.SetContainerID(cnr) hdr.SetType(objectSDK.TypeRegular) - hdr.SetVersion(&ver) + hdr.SetVersion(ver) return hdr } diff --git a/object/type.go b/object/type.go index 29328d3..4cd9cd7 100644 --- a/object/type.go +++ b/object/type.go @@ -1,10 +1,10 @@ package object import ( - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" + v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object/grpc" ) -type Type object.Type +type Type v2object.ObjectType const ( TypeRegular Type = iota @@ -13,11 +13,11 @@ const ( TypeLock ) -func (t Type) ToV2() object.Type { - return object.Type(t) +func (t Type) ToV2() v2object.ObjectType { + return v2object.ObjectType(t) } -func TypeFromV2(t object.Type) Type { +func TypeFromV2(t v2object.ObjectType) Type { return Type(t) } @@ -36,7 +36,7 @@ func (t Type) String() string { // // Returns true if s was parsed successfully. func (t *Type) FromString(s string) bool { - var g object.Type + var g v2object.ObjectType ok := g.FromString(s) diff --git a/object/type_test.go b/object/type_test.go index 5faa936..b646aca 100644 --- a/object/type_test.go +++ b/object/type_test.go @@ -3,7 +3,7 @@ package object_test import ( "testing" - v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" + v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object/grpc" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" "github.com/stretchr/testify/require" ) @@ -11,19 +11,19 @@ import ( func TestType_ToV2(t *testing.T) { typs := []struct { t object.Type - t2 v2object.Type + t2 v2object.ObjectType }{ { t: object.TypeRegular, - t2: v2object.TypeRegular, + t2: v2object.ObjectType_REGULAR, }, { t: object.TypeTombstone, - t2: v2object.TypeTombstone, + t2: v2object.ObjectType_TOMBSTONE, }, { t: object.TypeLock, - t2: v2object.TypeLock, + t2: v2object.ObjectType_LOCK, }, } diff --git a/pool/mock_test.go b/pool/mock_test.go index 9df107d..d3f08d9 100644 --- a/pool/mock_test.go +++ b/pool/mock_test.go @@ -7,7 +7,7 @@ import ( "go.uber.org/zap" - sessionv2 "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-sdk-go/accounting" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container" @@ -67,12 +67,12 @@ func (m *mockClient) statusOnGetObject(st apistatus.Status) { } func newToken(key ecdsa.PrivateKey) *session.Object { - var tok session.Object + tok := session.NewObject() tok.SetID(uuid.New()) pk := frostfsecdsa.PublicKey(key.PublicKey) tok.SetAuthKey(&pk) - return &tok + return tok } func (m *mockClient) balanceGet(context.Context, PrmBalanceGet) (accounting.Decimal, error) { @@ -104,7 +104,7 @@ func (m *mockClient) containerSetEACL(context.Context, PrmContainerSetEACL) erro } func (m *mockClient) endpointInfo(ctx context.Context, _ prmEndpointInfo) (netmap.NodeInfo, error) { - var ni netmap.NodeInfo + ni := netmap.NewNodeInfo() if m.errorOnEndpointInfo { return ni, m.handleError(ctx, nil, errors.New("error")) @@ -162,11 +162,11 @@ func (m *mockClient) sessionCreate(ctx context.Context, _ prmCreateSession) (res tok := newToken(m.key) - var v2tok sessionv2.Token + var v2tok sessiongrpc.SessionToken tok.WriteToV2(&v2tok) return resCreateSession{ - id: v2tok.GetBody().GetID(), + id: v2tok.GetBody().GetId(), sessionKey: v2tok.GetBody().GetSessionKey(), }, nil } diff --git a/pool/pool.go b/pool/pool.go index 2f662d3..e45aa70 100644 --- a/pool/pool.go +++ b/pool/pool.go @@ -452,7 +452,7 @@ func (c *clientWrapper) containerGet(ctx context.Context, prm PrmContainerGet) ( return container.Container{}, fmt.Errorf("container get on client: %w", err) } - return res.Container(), nil + return *res.Container(), nil } // containerList invokes sdkClient.ContainerList parse response status to error and return result as is. @@ -543,7 +543,7 @@ func (c *clientWrapper) containerSetEACL(ctx context.Context, prm PrmContainerSe } var cliPrm sdkClient.PrmContainerSetEACL - cliPrm.SetTable(prm.table) + cliPrm.SetTable(&prm.table) if prm.sessionSet { cliPrm.WithinSession(prm.session) @@ -626,7 +626,7 @@ func (c *clientWrapper) objectPut(ctx context.Context, prm PrmObjectPut) (oid.ID return oid.ID{}, err } - var cliPrm sdkClient.PrmObjectPutInit + cliPrm := sdkClient.NewPrmObjectPutInit() cliPrm.SetCopiesNumberByVectors(prm.copiesNumber) if prm.stoken != nil { cliPrm.WithinSession(*prm.stoken) @@ -709,7 +709,7 @@ func (c *clientWrapper) objectDelete(ctx context.Context, prm PrmObjectDelete) e return err } - var cliPrm sdkClient.PrmObjectDelete + cliPrm := sdkClient.NewPrmObjectDelete() cliPrm.FromContainer(prm.addr.Container()) cliPrm.ByID(prm.addr.Object()) @@ -745,7 +745,7 @@ func (c *clientWrapper) objectGet(ctx context.Context, prm PrmObjectGet) (ResGet return ResGetObject{}, err } - var cliPrm sdkClient.PrmObjectGet + cliPrm := sdkClient.NewPrmObjectGet() cliPrm.FromContainer(prm.addr.Container()) cliPrm.ByID(prm.addr.Object()) @@ -798,7 +798,7 @@ func (c *clientWrapper) objectHead(ctx context.Context, prm PrmObjectHead) (obje return object.Object{}, err } - var cliPrm sdkClient.PrmObjectHead + cliPrm := sdkClient.NewPrmObjectHead() cliPrm.FromContainer(prm.addr.Container()) cliPrm.ByID(prm.addr.Object()) if prm.raw { @@ -843,7 +843,7 @@ func (c *clientWrapper) objectRange(ctx context.Context, prm PrmObjectRange) (Re return ResObjectRange{}, err } - var cliPrm sdkClient.PrmObjectRange + cliPrm := sdkClient.NewPrmObjectRange() cliPrm.FromContainer(prm.addr.Container()) cliPrm.ByID(prm.addr.Object()) cliPrm.SetOffset(prm.off) @@ -883,7 +883,7 @@ func (c *clientWrapper) objectSearch(ctx context.Context, prm PrmObjectSearch) ( return ResObjectSearch{}, err } - var cliPrm sdkClient.PrmObjectSearch + cliPrm := sdkClient.NewPrmObjectSearch() cliPrm.InContainer(prm.cnrID) cliPrm.SetFilters(prm.filters) @@ -1293,6 +1293,12 @@ type PrmObjectPut struct { copiesNumber []uint32 } +func NewPrmObjectPut() PrmObjectPut { + return PrmObjectPut{ + hdr: *object.New(), + } +} + // SetHeader specifies header of the object. func (x *PrmObjectPut) SetHeader(hdr object.Object) { x.hdr = hdr @@ -2551,7 +2557,7 @@ func (p *Pool) Close() { // // Returns any error that does not allow reading configuration // from the network. -func SyncContainerWithNetwork(ctx context.Context, cnr *container.Container, p *Pool) error { +func SyncContainerWithNetwork(ctx context.Context, cnr container.Container, p *Pool) error { ni, err := p.NetworkInfo(ctx) if err != nil { return fmt.Errorf("network info: %w", err) diff --git a/pool/tree/pool_signature.go b/pool/tree/pool_signature.go index 0b3a2f6..3805df4 100644 --- a/pool/tree/pool_signature.go +++ b/pool/tree/pool_signature.go @@ -2,7 +2,7 @@ package tree import ( crypto "git.frostfs.info/TrueCloudLab/frostfs-crypto" - "google.golang.org/protobuf/proto" + "github.com/golang/protobuf/proto" ) func (p *Pool) signData(buf []byte, f func(key, sign []byte)) error { diff --git a/session/common.go b/session/common.go index b103b59..597753a 100644 --- a/session/common.go +++ b/session/common.go @@ -6,12 +6,14 @@ import ( "errors" "fmt" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" + refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc" + session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session/grpc" 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/user" + "github.com/golang/protobuf/proto" "github.com/google/uuid" + "google.golang.org/protobuf/encoding/protojson" ) type commonData struct { @@ -27,16 +29,22 @@ type commonData struct { authKey []byte sigSet bool - sig refs.Signature + sig *refs.Signature } -type contextReader func(session.TokenContext, bool) error +func newCommonData() commonData { + return commonData{ + sig: new(refs.Signature), + } +} + +type contextReader func(*session.SessionToken_Body, bool) error // reads commonData and custom context from the session.Token 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. // Calls contextReader if session context is set. Passes checkFieldPresence into contextReader. -func (x *commonData) readFromV2(m session.Token, checkFieldPresence bool, r contextReader) error { +func (x *commonData) readFromV2(m *session.SessionToken, checkFieldPresence bool, r contextReader) error { var err error body := m.GetBody() @@ -44,7 +52,7 @@ func (x *commonData) readFromV2(m session.Token, checkFieldPresence bool, r cont return errors.New("missing token body") } - binID := body.GetID() + binID := body.GetId() if x.idSet = len(binID) > 0; x.idSet { err = x.id.UnmarshalBinary(binID) if err != nil { @@ -56,9 +64,9 @@ func (x *commonData) readFromV2(m session.Token, checkFieldPresence bool, r cont return errors.New("missing session ID") } - issuer := body.GetOwnerID() + issuer := body.GetOwnerId() if x.issuerSet = issuer != nil; x.issuerSet { - err = x.issuer.ReadFromV2(*issuer) + err = x.issuer.ReadFromV2(issuer) if err != nil { return fmt.Errorf("invalid session issuer: %w", err) } @@ -80,19 +88,14 @@ func (x *commonData) readFromV2(m session.Token, checkFieldPresence bool, r cont return errors.New("missing session public key") } - c := body.GetContext() - if c != nil { - err = r(c, checkFieldPresence) - if err != nil { - return fmt.Errorf("invalid context: %w", err) - } - } else if checkFieldPresence { - return errors.New("missing session context") + err = r(body, checkFieldPresence) + if err != nil { + return fmt.Errorf("invalid context: %w", err) } sig := m.GetSignature() if x.sigSet = sig != nil; sig != nil { - x.sig = *sig + x.sig = sig } else if checkFieldPresence { return errors.New("missing body signature") } @@ -100,10 +103,10 @@ func (x *commonData) readFromV2(m session.Token, checkFieldPresence bool, r cont return nil } -type contextWriter func() session.TokenContext +type contextWriter func(*session.SessionToken_Body) -func (x commonData) fillBody(w contextWriter) *session.TokenBody { - var body session.TokenBody +func (x commonData) fillBody(w contextWriter) *session.SessionToken_Body { + body := new(session.SessionToken_Body) if x.idSet { binID, err := x.id.MarshalBinary() @@ -111,33 +114,33 @@ func (x commonData) fillBody(w contextWriter) *session.TokenBody { panic(fmt.Sprintf("unexpected error from UUID.MarshalBinary: %v", err)) } - body.SetID(binID) + body.SetId(binID) } if x.issuerSet { var issuer refs.OwnerID x.issuer.WriteToV2(&issuer) - body.SetOwnerID(&issuer) + body.SetOwnerId(&issuer) } if x.lifetimeSet { - var lifetime session.TokenLifetime + lifetime := new(session.SessionToken_Body_TokenLifetime) lifetime.SetIat(x.iat) lifetime.SetNbf(x.nbf) lifetime.SetExp(x.exp) - body.SetLifetime(&lifetime) + body.SetLifetime(lifetime) } body.SetSessionKey(x.authKey) + w(body) - body.SetContext(w()) - - return &body + return body } -func (x commonData) writeToV2(m *session.Token, w contextWriter) { +func (x commonData) writeToV2(m *session.SessionToken, w contextWriter) { + m.Reset() body := x.fillBody(w) m.SetBody(body) @@ -145,13 +148,13 @@ func (x commonData) writeToV2(m *session.Token, w contextWriter) { var sig *refs.Signature if x.sigSet { - sig = &x.sig + sig = x.sig } m.SetSignature(sig) } -func (x commonData) signedData(w contextWriter) []byte { +func (x *commonData) signedData(w contextWriter) []byte { return x.fillBody(w).StableMarshal(nil) } @@ -159,41 +162,44 @@ func (x *commonData) sign(key ecdsa.PrivateKey, w contextWriter) error { user.IDFromKey(&x.issuer, key.PublicKey) x.issuerSet = true - var sig frostfscrypto.Signature + sig := frostfscrypto.NewSignature() err := sig.Calculate(frostfsecdsa.Signer(key), x.signedData(w)) if err != nil { return err } - sig.WriteToV2(&x.sig) + if x.sig == nil { + x.sig = new(refs.Signature) + } + sig.WriteToV2(x.sig) x.sigSet = true return nil } -func (x commonData) verifySignature(w contextWriter) bool { +func (x *commonData) verifySignature(w contextWriter) bool { if !x.sigSet { return false } - var sig frostfscrypto.Signature + sig := frostfscrypto.NewSignature() // TODO: (#233) check owner<->key relation return sig.ReadFromV2(x.sig) == nil && sig.Verify(x.signedData(w)) } -func (x commonData) marshal(w contextWriter) []byte { - var m session.Token - x.writeToV2(&m, w) +func (x *commonData) marshal(w contextWriter) []byte { + m := new(session.SessionToken) + x.writeToV2(m, w) return m.StableMarshal(nil) } func (x *commonData) unmarshal(data []byte, r contextReader) error { - var m session.Token + m := new(session.SessionToken) - err := m.Unmarshal(data) + err := proto.Unmarshal(data, m) if err != nil { return err } @@ -201,17 +207,17 @@ func (x *commonData) unmarshal(data []byte, r contextReader) error { return x.readFromV2(m, false, r) } -func (x commonData) marshalJSON(w contextWriter) ([]byte, error) { - var m session.Token - x.writeToV2(&m, w) +func (x *commonData) marshalJSON(w contextWriter) ([]byte, error) { + m := new(session.SessionToken) + x.writeToV2(m, w) - return m.MarshalJSON() + return protojson.Marshal(m) } func (x *commonData) unmarshalJSON(data []byte, r contextReader) error { - var m session.Token + m := new(session.SessionToken) - err := m.UnmarshalJSON(data) + err := protojson.Unmarshal(data, m) if err != nil { return err } @@ -258,7 +264,7 @@ func (x *commonData) SetIat(iat uint64) { x.lifetimeSet = true } -func (x commonData) expiredAt(epoch uint64) bool { +func (x *commonData) expiredAt(epoch uint64) bool { return !x.lifetimeSet || x.exp < epoch } @@ -267,7 +273,7 @@ func (x commonData) expiredAt(epoch uint64) bool { // Zero session is invalid in any epoch. // // See also SetExp, SetNbf, SetIat. -func (x commonData) InvalidAt(epoch uint64) bool { +func (x *commonData) InvalidAt(epoch uint64) bool { return x.expiredAt(epoch) || x.nbf > epoch || x.iat > epoch } @@ -291,7 +297,7 @@ func (x *commonData) SetID(id uuid.UUID) { // but most likely not suitable. // // See also SetID. -func (x commonData) ID() uuid.UUID { +func (x *commonData) ID() uuid.UUID { if x.idSet { return x.id } @@ -312,7 +318,7 @@ func (x *commonData) SetAuthKey(key frostfscrypto.PublicKey) { // Zero session fails the check. // // See also SetAuthKey. -func (x commonData) AssertAuthKey(key frostfscrypto.PublicKey) bool { +func (x *commonData) AssertAuthKey(key frostfscrypto.PublicKey) bool { bKey := make([]byte, key.MaxEncodedSize()) bKey = bKey[:key.Encode(bKey)] @@ -325,7 +331,7 @@ func (x commonData) AssertAuthKey(key frostfscrypto.PublicKey) bool { // Issuer returns zero user.ID. // // See also Sign. -func (x commonData) Issuer() user.ID { +func (x *commonData) Issuer() user.ID { if x.issuerSet { return x.issuer } diff --git a/session/container.go b/session/container.go index 45c5ff8..1f97aec 100644 --- a/session/container.go +++ b/session/container.go @@ -5,8 +5,8 @@ import ( "errors" "fmt" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" + refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc" + session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session/grpc" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user" @@ -21,7 +21,7 @@ import ( // Container is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session.Token // message. See ReadFromV2 / WriteToV2 methods. // -// Instances can be created using built-in var declaration. +// Instances must be created by NewContainer() constructor. type Container struct { commonData @@ -31,19 +31,33 @@ type Container struct { cnr cid.ID } +func NewContainer() Container { + return Container{ + commonData: newCommonData(), + } +} + // readContext is a contextReader needed for commonData methods. -func (x *Container) readContext(c session.TokenContext, checkFieldPresence bool) error { - cCnr, ok := c.(*session.ContainerSessionContext) - if !ok || cCnr == nil { +func (x *Container) readContext(b *session.SessionToken_Body, checkFieldPresence bool) error { + c := b.GetContext() + if c == nil { + if checkFieldPresence { + return errors.New("missing session context") + } + return nil + } + stbc, ok := c.(*session.SessionToken_Body_Container) + if !ok || stbc == nil { return fmt.Errorf("invalid context %T", c) } + cCnr := stbc.Container - x.cnrSet = !cCnr.Wildcard() - cnr := cCnr.ContainerID() + x.cnrSet = !cCnr.GetWildcard() + cnr := cCnr.GetContainerId() if x.cnrSet { if cnr != nil { - err := x.cnr.ReadFromV2(*cnr) + err := x.cnr.ReadFromV2(cnr) if err != nil { return fmt.Errorf("invalid container ID: %w", err) } @@ -54,12 +68,12 @@ func (x *Container) readContext(c session.TokenContext, checkFieldPresence bool) return errors.New("container conflicts with wildcard flag") } - x.verb = ContainerVerb(cCnr.Verb()) + x.verb = ContainerVerb(cCnr.GetVerb()) return nil } -func (x *Container) readFromV2(m session.Token, checkFieldPresence bool) error { +func (x *Container) readFromV2(m *session.SessionToken, checkFieldPresence bool) error { return x.commonData.readFromV2(m, checkFieldPresence, x.readContext) } @@ -67,30 +81,35 @@ func (x *Container) readFromV2(m session.Token, checkFieldPresence bool) error { // message conforms to FrostFS API V2 protocol. // // See also WriteToV2. -func (x *Container) ReadFromV2(m session.Token) error { +func (x *Container) ReadFromV2(m *session.SessionToken) error { + if x.sig == nil { + x.sig = new(refs.Signature) + } return x.readFromV2(m, true) } -func (x Container) writeContext() session.TokenContext { - var c session.ContainerSessionContext - c.SetWildcard(!x.cnrSet) - c.SetVerb(session.ContainerSessionVerb(x.verb)) +func (x Container) writeContext(b *session.SessionToken_Body) { + c := new(session.SessionToken_Body_Container) + c.Container = new(session.ContainerSessionContext) + c.Container.SetWildcard(!x.cnrSet) + c.Container.SetVerb(session.ContainerSessionContext_Verb(x.verb)) if x.cnrSet { var cnr refs.ContainerID x.cnr.WriteToV2(&cnr) - c.SetContainerID(&cnr) + c.Container.SetContainerId(&cnr) } - return &c + b.Context = c } // WriteToV2 writes Container to the session.Token message. // The message must not be nil. // -// See also ReadFromV2. -func (x Container) WriteToV2(m *session.Token) { +// See also ReadFrom. +func (x Container) WriteToV2(m *session.SessionToken) { + m.Reset() x.writeToV2(m, x.writeContext) } @@ -204,12 +223,12 @@ func IssuedBy(cnr Container, id user.ID) bool { // VerifySessionDataSignature verifies signature of the session data. In practice, // the method is used to authenticate an operation with session data. func (x Container) VerifySessionDataSignature(data, signature []byte) bool { - var sigV2 refs.Signature + sigV2 := new(refs.Signature) sigV2.SetKey(x.authKey) - sigV2.SetScheme(refs.ECDSA_RFC6979_SHA256) + sigV2.SetScheme(refs.SignatureScheme_ECDSA_RFC6979_SHA256) sigV2.SetSign(signature) - var sig frostfscrypto.Signature + sig := frostfscrypto.NewSignature() return sig.ReadFromV2(sigV2) == nil && sig.Verify(data) } diff --git a/session/container_test.go b/session/container_test.go index a152e31..ad2bb80 100644 --- a/session/container_test.go +++ b/session/container_test.go @@ -6,8 +6,8 @@ import ( "math/rand" "testing" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" - v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" + refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc" + sessiongrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session/grpc" cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test" frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto" frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa" @@ -21,36 +21,36 @@ import ( ) func TestContainerProtocolV2(t *testing.T) { - var validV2 v2session.Token + validV2 := new(sessiongrpc.SessionToken) - var body v2session.TokenBody - validV2.SetBody(&body) + body := new(sessiongrpc.SessionToken_Body) + validV2.SetBody(body) // ID id := uuid.New() binID, err := id.MarshalBinary() require.NoError(t, err) restoreID := func() { - body.SetID(binID) + body.SetId(binID) } restoreID() // Owner usr := *usertest.ID() - var usrV2 refs.OwnerID + var usrV2 refsgrpc.OwnerID usr.WriteToV2(&usrV2) restoreUser := func() { - body.SetOwnerID(&usrV2) + body.SetOwnerId(&usrV2) } restoreUser() // Lifetime - var lifetime v2session.TokenLifetime + lifetime := new(sessiongrpc.SessionToken_Body_TokenLifetime) lifetime.SetIat(1) lifetime.SetNbf(2) lifetime.SetExp(3) restoreLifetime := func() { - body.SetLifetime(&lifetime) + body.SetLifetime(lifetime) } restoreLifetime() @@ -66,18 +66,18 @@ func TestContainerProtocolV2(t *testing.T) { // Context cnr := cidtest.ID() - var cnrV2 refs.ContainerID + var cnrV2 refsgrpc.ContainerID cnr.WriteToV2(&cnrV2) - var cCnr v2session.ContainerSessionContext + var cCnr sessiongrpc.ContainerSessionContext restoreCtx := func() { - cCnr.SetContainerID(&cnrV2) + cCnr.SetContainerId(&cnrV2) cCnr.SetWildcard(false) - body.SetContext(&cCnr) + body.SetContainerSessionContext(&cCnr) } restoreCtx() // Signature - var sig refs.Signature + var sig refsgrpc.Signature restoreSig := func() { validV2.SetSignature(&sig) } @@ -90,7 +90,7 @@ func TestContainerProtocolV2(t *testing.T) { corrupt []func() restore func() assert func(session.Container) - breakSign func(*v2session.Token) + breakSign func(*sessiongrpc.SessionToken) }{ { name: "Signature", @@ -105,22 +105,22 @@ func TestContainerProtocolV2(t *testing.T) { name: "ID", corrupt: []func(){ func() { - body.SetID([]byte{1, 2, 3}) + body.SetId([]byte{1, 2, 3}) }, func() { id, err := uuid.NewDCEPerson() require.NoError(t, err) bindID, err := id.MarshalBinary() require.NoError(t, err) - body.SetID(bindID) + body.SetId(bindID) }, }, restore: restoreID, assert: func(val session.Container) { require.Equal(t, id, val.ID()) }, - breakSign: func(m *v2session.Token) { - id := m.GetBody().GetID() + breakSign: func(m *sessiongrpc.SessionToken) { + id := m.GetBody().GetId() id[len(id)-1]++ }, }, @@ -128,17 +128,17 @@ func TestContainerProtocolV2(t *testing.T) { name: "User", corrupt: []func(){ func() { - var brokenUsrV2 refs.OwnerID + var brokenUsrV2 refsgrpc.OwnerID brokenUsrV2.SetValue(append(usrV2.GetValue(), 1)) - body.SetOwnerID(&brokenUsrV2) + body.SetOwnerId(&brokenUsrV2) }, }, restore: restoreUser, assert: func(val session.Container) { require.Equal(t, usr, val.Issuer()) }, - breakSign: func(m *v2session.Token) { - id := m.GetBody().GetOwnerID().GetValue() + breakSign: func(m *sessiongrpc.SessionToken) { + id := m.GetBody().GetOwnerId().GetValue() copy(id, usertest.ID().WalletBytes()) }, }, @@ -156,7 +156,7 @@ func TestContainerProtocolV2(t *testing.T) { require.False(t, val.InvalidAt(3)) require.True(t, val.InvalidAt(4)) }, - breakSign: func(m *v2session.Token) { + breakSign: func(m *sessiongrpc.SessionToken) { lt := m.GetBody().GetLifetime() lt.SetIat(lt.GetIat() + 1) }, @@ -175,7 +175,7 @@ func TestContainerProtocolV2(t *testing.T) { assert: func(val session.Container) { require.True(t, val.AssertAuthKey(&authKey)) }, - breakSign: func(m *v2session.Token) { + breakSign: func(m *sessiongrpc.SessionToken) { body := m.GetBody() key := body.GetSessionKey() cp := slice.Copy(key) @@ -187,18 +187,18 @@ func TestContainerProtocolV2(t *testing.T) { name: "Context", corrupt: []func(){ func() { - body.SetContext(nil) + body.SetContainerSessionContext(nil) }, func() { cCnr.SetWildcard(true) }, func() { - cCnr.SetContainerID(nil) + cCnr.SetContainerId(nil) }, func() { - var brokenCnr refs.ContainerID + var brokenCnr refsgrpc.ContainerID brokenCnr.SetValue(append(cnrV2.GetValue(), 1)) - cCnr.SetContainerID(&brokenCnr) + cCnr.SetContainerId(&brokenCnr) }, }, restore: restoreCtx, @@ -206,8 +206,8 @@ func TestContainerProtocolV2(t *testing.T) { require.True(t, val.AppliedTo(cnr)) require.False(t, val.AppliedTo(cidtest.ID())) }, - breakSign: func(m *v2session.Token) { - cnr := m.GetBody().GetContext().(*v2session.ContainerSessionContext).ContainerID().GetValue() + breakSign: func(m *sessiongrpc.SessionToken) { + cnr := m.GetBody().GetContext().(*sessiongrpc.SessionToken_Body_Container).Container.GetContainerId().GetValue() cnr[len(cnr)-1]++ }, }, @@ -229,14 +229,14 @@ func TestContainerProtocolV2(t *testing.T) { require.NoError(t, val.Sign(signer), testcase.name) require.True(t, val.VerifySignature(), testcase.name) - var signedV2 v2session.Token - val.WriteToV2(&signedV2) + signedV2 := new(sessiongrpc.SessionToken) + val.WriteToV2(signedV2) - var restored session.Container + restored := new(session.Container) require.NoError(t, restored.ReadFromV2(signedV2), testcase.name) require.True(t, restored.VerifySignature(), testcase.name) - testcase.breakSign(&signedV2) + testcase.breakSign(signedV2) require.NoError(t, restored.ReadFromV2(signedV2), testcase.name) require.False(t, restored.VerifySignature(), testcase.name) @@ -248,10 +248,10 @@ func TestContainerProtocolV2(t *testing.T) { func TestContainer_WriteToV2(t *testing.T) { var val session.Container - assert := func(baseAssert func(v2session.Token)) { - var m v2session.Token + assert := func(baseAssert func(*sessiongrpc.SessionToken)) { + var m sessiongrpc.SessionToken val.WriteToV2(&m) - baseAssert(m) + baseAssert(&m) } // ID @@ -261,8 +261,8 @@ func TestContainer_WriteToV2(t *testing.T) { require.NoError(t, err) val.SetID(id) - assert(func(m v2session.Token) { - require.Equal(t, binID, m.GetBody().GetID()) + assert(func(m *sessiongrpc.SessionToken) { + require.Equal(t, binID, m.GetBody().GetId()) }) // Owner/Signature @@ -273,11 +273,11 @@ func TestContainer_WriteToV2(t *testing.T) { var usr user.ID user.IDFromKey(&usr, signer.PublicKey) - var usrV2 refs.OwnerID + var usrV2 refsgrpc.OwnerID usr.WriteToV2(&usrV2) - assert(func(m v2session.Token) { - require.Equal(t, &usrV2, m.GetBody().GetOwnerID()) + assert(func(m *sessiongrpc.SessionToken) { + require.Equal(t, &usrV2, m.GetBody().GetOwnerId()) sig := m.GetSignature() require.NotZero(t, sig.GetKey()) @@ -290,7 +290,7 @@ func TestContainer_WriteToV2(t *testing.T) { val.SetNbf(nbf) val.SetExp(exp) - assert(func(m v2session.Token) { + assert(func(m *sessiongrpc.SessionToken) { lt := m.GetBody().GetLifetime() require.EqualValues(t, iat, lt.GetIat()) require.EqualValues(t, nbf, lt.GetNbf()) @@ -298,38 +298,38 @@ func TestContainer_WriteToV2(t *testing.T) { }) // Context - assert(func(m v2session.Token) { - cCnr, ok := m.GetBody().GetContext().(*v2session.ContainerSessionContext) + assert(func(m *sessiongrpc.SessionToken) { + cCnr, ok := m.GetBody().GetContext().(*sessiongrpc.SessionToken_Body_Container) require.True(t, ok) - require.True(t, cCnr.Wildcard()) - require.Zero(t, cCnr.ContainerID()) + require.True(t, cCnr.Container.GetWildcard()) + require.Zero(t, cCnr.Container.GetContainerId()) }) cnr := cidtest.ID() - var cnrV2 refs.ContainerID + var cnrV2 refsgrpc.ContainerID cnr.WriteToV2(&cnrV2) val.ApplyOnlyTo(cnr) - assert(func(m v2session.Token) { - cCnr, ok := m.GetBody().GetContext().(*v2session.ContainerSessionContext) + assert(func(m *sessiongrpc.SessionToken) { + cCnr, ok := m.GetBody().GetContext().(*sessiongrpc.SessionToken_Body_Container) require.True(t, ok) - require.False(t, cCnr.Wildcard()) - require.Equal(t, &cnrV2, cCnr.ContainerID()) + require.False(t, cCnr.Container.GetWildcard()) + require.Equal(t, &cnrV2, cCnr.Container.GetContainerId()) }) } func TestContainer_ApplyOnlyTo(t *testing.T) { var val session.Container - var m v2session.Token + var m sessiongrpc.SessionToken filled := sessiontest.Container() assertDefaults := func() { - cCnr, ok := m.GetBody().GetContext().(*v2session.ContainerSessionContext) + cCnr, ok := m.GetBody().GetContext().(*sessiongrpc.SessionToken_Body_Container) require.True(t, ok) - require.True(t, cCnr.Wildcard()) - require.Zero(t, cCnr.ContainerID()) + require.True(t, cCnr.Container.GetWildcard()) + require.Zero(t, cCnr.Container.GetContainerId()) } assertBinary := func(baseAssert func()) { @@ -359,7 +359,7 @@ func TestContainer_ApplyOnlyTo(t *testing.T) { cnr := cidtest.ID() - var cnrV2 refs.ContainerID + var cnrV2 refsgrpc.ContainerID cnr.WriteToV2(&cnrV2) val.ApplyOnlyTo(cnr) @@ -367,10 +367,10 @@ func TestContainer_ApplyOnlyTo(t *testing.T) { val.WriteToV2(&m) assertCnr := func() { - cCnr, ok := m.GetBody().GetContext().(*v2session.ContainerSessionContext) + cCnr, ok := m.GetBody().GetContext().(*sessiongrpc.SessionToken_Body_Container) require.True(t, ok) - require.False(t, cCnr.Wildcard()) - require.Equal(t, &cnrV2, cCnr.ContainerID()) + require.False(t, cCnr.Container.GetWildcard()) + require.Equal(t, &cnrV2, cCnr.Container.GetContainerId()) } assertCnr() @@ -441,13 +441,13 @@ func TestContainer_AssertAuthKey(t *testing.T) { func TestContainer_ForVerb(t *testing.T) { var val session.Container - var m v2session.Token + var m sessiongrpc.SessionToken filled := sessiontest.Container() assertDefaults := func() { - cCnr, ok := m.GetBody().GetContext().(*v2session.ContainerSessionContext) + cCnr, ok := m.GetBody().GetContext().(*sessiongrpc.SessionToken_Body_Container) require.True(t, ok) - require.Zero(t, cCnr.Verb()) + require.Zero(t, cCnr.Container.GetVerb()) } assertBinary := func(baseAssert func()) { @@ -475,16 +475,16 @@ func TestContainer_ForVerb(t *testing.T) { // set value - assertVerb := func(verb v2session.ContainerSessionVerb) { - cCnr, ok := m.GetBody().GetContext().(*v2session.ContainerSessionContext) + assertVerb := func(verb sessiongrpc.ContainerSessionContext_Verb) { + cCnr, ok := m.GetBody().GetContext().(*sessiongrpc.SessionToken_Body_Container) require.True(t, ok) - require.Equal(t, verb, cCnr.Verb()) + require.Equal(t, verb, cCnr.Container.GetVerb()) } - for from, to := range map[session.ContainerVerb]v2session.ContainerSessionVerb{ - session.VerbContainerPut: v2session.ContainerVerbPut, - session.VerbContainerDelete: v2session.ContainerVerbDelete, - session.VerbContainerSetEACL: v2session.ContainerVerbSetEACL, + for from, to := range map[session.ContainerVerb]sessiongrpc.ContainerSessionContext_Verb{ + session.VerbContainerPut: sessiongrpc.ContainerSessionContext_PUT, + session.VerbContainerDelete: sessiongrpc.ContainerSessionContext_DELETE, + session.VerbContainerSetEACL: sessiongrpc.ContainerSessionContext_SETEACL, } { val.ForVerb(from) @@ -550,15 +550,15 @@ func TestContainer_Sign(t *testing.T) { func TestContainer_VerifyDataSignature(t *testing.T) { signer := randSigner() - var tok session.Container + tok := session.NewContainer() data := make([]byte, 100) rand.Read(data) - var sig frostfscrypto.Signature + sig := frostfscrypto.NewSignature() require.NoError(t, sig.Calculate(frostfsecdsa.SignerRFC6979(signer), data)) - var sigV2 refs.Signature + var sigV2 refsgrpc.Signature sig.WriteToV2(&sigV2) require.False(t, tok.VerifySessionDataSignature(data, sigV2.GetSign())) diff --git a/session/doc.go b/session/doc.go index 12ec0c4..2f4161f 100644 --- a/session/doc.go +++ b/session/doc.go @@ -39,7 +39,7 @@ On server side: // recv msg - var tok session.Container + tok := session.NewContainer() tok.ReadFromV2(msg) // process cnr diff --git a/session/object.go b/session/object.go index 86ea7cb..2e461c7 100644 --- a/session/object.go +++ b/session/object.go @@ -5,22 +5,23 @@ import ( "errors" "fmt" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" + refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc" + sessiongrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session/grpc" 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/util/slices" ) -// Object represents token of the FrostFS Object session. A session is opened +// Object represents token of the FrostFS Object sessiongrpc. A session is opened // between any two sides of the system, and implements a mechanism for transferring // the power of attorney of actions to another network member. The session has a // limited validity period, and applies to a strictly defined set of operations. // See methods for details. // -// Object is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session.Token -// message. See ReadFromV2 / WriteToV2 methods. +// Object is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/sessiongrpc.Token +// message. See ReadFrom / WriteToV2 methods. // -// Instances can be created using built-in var declaration. +// Instances must be created by NewObject() constructor. type Object struct { commonData @@ -32,17 +33,31 @@ type Object struct { objs []oid.ID } -func (x *Object) readContext(c session.TokenContext, checkFieldPresence bool) error { - cObj, ok := c.(*session.ObjectSessionContext) - if !ok || cObj == nil { +func NewObject() *Object { + return &Object{ + commonData: newCommonData(), + } +} + +func (x *Object) readContext(b *sessiongrpc.SessionToken_Body, checkFieldPresence bool) error { + c := b.GetContext() + if c == nil { + if checkFieldPresence { + return errors.New("missing session context") + } + return nil + } + stbc, ok := c.(*sessiongrpc.SessionToken_Body_Object) + if !ok || stbc == nil { return fmt.Errorf("invalid context %T", c) } + cObj := stbc.Object var err error - cnr := cObj.GetContainer() + cnr := cObj.GetTarget().GetContainer() if x.cnrSet = cnr != nil; x.cnrSet { - err := x.cnr.ReadFromV2(*cnr) + err := x.cnr.ReadFromV2(cnr) if err != nil { return fmt.Errorf("invalid container ID: %w", err) } @@ -50,7 +65,7 @@ func (x *Object) readContext(c session.TokenContext, checkFieldPresence bool) er return errors.New("missing target container") } - objs := cObj.GetObjects() + objs := cObj.GetTarget().GetObjects() if objs != nil { x.objs = make([]oid.ID, len(objs)) @@ -69,51 +84,52 @@ func (x *Object) readContext(c session.TokenContext, checkFieldPresence bool) er return nil } -func (x *Object) readFromV2(m session.Token, checkFieldPresence bool) error { +func (x *Object) readFromV2(m *sessiongrpc.SessionToken, checkFieldPresence bool) error { return x.commonData.readFromV2(m, checkFieldPresence, x.readContext) } -// ReadFromV2 reads Object from the session.Token message. Checks if the +// ReadFrom reads Object from the sessiongrpc.Token message. Checks if the // message conforms to FrostFS API V2 protocol. // // See also WriteToV2. -func (x *Object) ReadFromV2(m session.Token) error { +func (x *Object) ReadFromV2(m *sessiongrpc.SessionToken) error { return x.readFromV2(m, true) } -func (x Object) writeContext() session.TokenContext { - var c session.ObjectSessionContext - c.SetVerb(session.ObjectSessionVerb(x.verb)) +func (x Object) writeContext(b *sessiongrpc.SessionToken_Body) { + c := new(sessiongrpc.SessionToken_Body_Object) + c.Object = new(sessiongrpc.ObjectSessionContext) + c.Object.SetVerb(sessiongrpc.ObjectSessionContext_Verb(x.verb)) if x.cnrSet || len(x.objs) > 0 { - var cnr *refs.ContainerID + var cnr *refsgrpc.ContainerID if x.cnrSet { - cnr = new(refs.ContainerID) + cnr = new(refsgrpc.ContainerID) x.cnr.WriteToV2(cnr) } - var objs []refs.ObjectID + var objs []*refsgrpc.ObjectID if x.objs != nil { - objs = make([]refs.ObjectID, len(x.objs)) - + objs = slices.MakePreallocPointerSlice[refsgrpc.ObjectID](len(x.objs)) for i := range x.objs { - x.objs[i].WriteToV2(&objs[i]) + x.objs[i].WriteToV2(objs[i]) } } - c.SetTarget(cnr, objs...) + c.Object.SetTarget(cnr, objs) } - return &c + b.Context = c } -// WriteToV2 writes Object to the session.Token message. +// WriteToV2 writes Object to the sessiongrpc.Token message. // The message must not be nil. // -// See also ReadFromV2. -func (x Object) WriteToV2(m *session.Token) { +// See also ReadFrom. +func (x Object) WriteToV2(m *sessiongrpc.SessionToken) { + m.Reset() x.writeToV2(m, x.writeContext) } @@ -122,7 +138,7 @@ func (x Object) WriteToV2(m *session.Token) { // // See also Unmarshal. func (x Object) Marshal() []byte { - var m session.Token + var m sessiongrpc.SessionToken x.WriteToV2(&m) return x.marshal(x.writeContext) diff --git a/session/object_test.go b/session/object_test.go index 7d1d77b..eef4554 100644 --- a/session/object_test.go +++ b/session/object_test.go @@ -7,8 +7,8 @@ import ( "math/rand" "testing" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" - v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" + refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc" + sessiongrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session/grpc" cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test" frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto" frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa" @@ -21,6 +21,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/util/slice" "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" ) func randSigner() ecdsa.PrivateKey { @@ -38,36 +39,36 @@ func randPublicKey() frostfscrypto.PublicKey { } func TestObjectProtocolV2(t *testing.T) { - var validV2 v2session.Token + validV2 := new(sessiongrpc.SessionToken) - var body v2session.TokenBody - validV2.SetBody(&body) + body := new(sessiongrpc.SessionToken_Body) + validV2.SetBody(body) // ID id := uuid.New() binID, err := id.MarshalBinary() require.NoError(t, err) restoreID := func() { - body.SetID(binID) + body.SetId(binID) } restoreID() // Owner usr := *usertest.ID() - var usrV2 refs.OwnerID + var usrV2 refsgrpc.OwnerID usr.WriteToV2(&usrV2) restoreUser := func() { - body.SetOwnerID(&usrV2) + body.SetOwnerId(&usrV2) } restoreUser() // Lifetime - var lifetime v2session.TokenLifetime + lifetime := new(sessiongrpc.SessionToken_Body_TokenLifetime) lifetime.SetIat(1) lifetime.SetNbf(2) lifetime.SetExp(3) restoreLifetime := func() { - body.SetLifetime(&lifetime) + body.SetLifetime(lifetime) } restoreLifetime() @@ -85,21 +86,21 @@ func TestObjectProtocolV2(t *testing.T) { cnr := cidtest.ID() obj1 := oidtest.ID() obj2 := oidtest.ID() - var cnrV2 refs.ContainerID + var cnrV2 refsgrpc.ContainerID cnr.WriteToV2(&cnrV2) - var obj1V2 refs.ObjectID + var obj1V2 refsgrpc.ObjectID obj1.WriteToV2(&obj1V2) - var obj2V2 refs.ObjectID + var obj2V2 refsgrpc.ObjectID obj2.WriteToV2(&obj2V2) - var cObj v2session.ObjectSessionContext + var cObj sessiongrpc.ObjectSessionContext restoreCtx := func() { - cObj.SetTarget(&cnrV2, obj1V2, obj2V2) - body.SetContext(&cObj) + cObj.SetTarget(&cnrV2, []*refsgrpc.ObjectID{&obj1V2, &obj2V2}) + body.SetObjectSessionContext(&cObj) } restoreCtx() // Signature - var sig refs.Signature + var sig refsgrpc.Signature restoreSig := func() { validV2.SetSignature(&sig) } @@ -112,7 +113,7 @@ func TestObjectProtocolV2(t *testing.T) { corrupt []func() restore func() assert func(session.Object) - breakSign func(*v2session.Token) + breakSign func(*sessiongrpc.SessionToken) }{ { name: "Signature", @@ -127,22 +128,22 @@ func TestObjectProtocolV2(t *testing.T) { name: "ID", corrupt: []func(){ func() { - body.SetID([]byte{1, 2, 3}) + body.SetId([]byte{1, 2, 3}) }, func() { id, err := uuid.NewDCEPerson() require.NoError(t, err) bindID, err := id.MarshalBinary() require.NoError(t, err) - body.SetID(bindID) + body.SetId(bindID) }, }, restore: restoreID, assert: func(val session.Object) { require.Equal(t, id, val.ID()) }, - breakSign: func(m *v2session.Token) { - id := m.GetBody().GetID() + breakSign: func(m *sessiongrpc.SessionToken) { + id := m.GetBody().GetId() id[len(id)-1]++ }, }, @@ -150,17 +151,17 @@ func TestObjectProtocolV2(t *testing.T) { name: "User", corrupt: []func(){ func() { - var brokenUsrV2 refs.OwnerID + var brokenUsrV2 refsgrpc.OwnerID brokenUsrV2.SetValue(append(usrV2.GetValue(), 1)) - body.SetOwnerID(&brokenUsrV2) + body.SetOwnerId(&brokenUsrV2) }, }, restore: restoreUser, assert: func(val session.Object) { require.Equal(t, usr, val.Issuer()) }, - breakSign: func(m *v2session.Token) { - id := m.GetBody().GetOwnerID().GetValue() + breakSign: func(m *sessiongrpc.SessionToken) { + id := m.GetBody().GetOwnerId().GetValue() copy(id, usertest.ID().WalletBytes()) }, }, @@ -178,7 +179,7 @@ func TestObjectProtocolV2(t *testing.T) { require.False(t, val.InvalidAt(3)) require.True(t, val.InvalidAt(4)) }, - breakSign: func(m *v2session.Token) { + breakSign: func(m *sessiongrpc.SessionToken) { lt := m.GetBody().GetLifetime() lt.SetIat(lt.GetIat() + 1) }, @@ -197,7 +198,7 @@ func TestObjectProtocolV2(t *testing.T) { assert: func(val session.Object) { require.True(t, val.AssertAuthKey(&authKey)) }, - breakSign: func(m *v2session.Token) { + breakSign: func(m *sessiongrpc.SessionToken) { body := m.GetBody() key := body.GetSessionKey() cp := slice.Copy(key) @@ -209,20 +210,20 @@ func TestObjectProtocolV2(t *testing.T) { name: "Context", corrupt: []func(){ func() { - body.SetContext(nil) + body.SetContainerSessionContext(nil) }, func() { - cObj.SetTarget(nil) + cObj.SetTarget(nil, nil) }, func() { - var brokenCnr refs.ContainerID + var brokenCnr refsgrpc.ContainerID brokenCnr.SetValue(append(cnrV2.GetValue(), 1)) - cObj.SetTarget(&brokenCnr) + cObj.SetTarget(&brokenCnr, cObj.Target.Objects) }, func() { - var brokenObj refs.ObjectID + var brokenObj refsgrpc.ObjectID brokenObj.SetValue(append(obj1V2.GetValue(), 1)) - cObj.SetTarget(&cnrV2, brokenObj) + cObj.SetTarget(&cnrV2, []*refsgrpc.ObjectID{&obj1V2, &brokenObj}) }, }, restore: restoreCtx, @@ -233,8 +234,8 @@ func TestObjectProtocolV2(t *testing.T) { require.True(t, val.AssertObject(obj2)) require.False(t, val.AssertObject(oidtest.ID())) }, - breakSign: func(m *v2session.Token) { - cnr := m.GetBody().GetContext().(*v2session.ObjectSessionContext).GetContainer().GetValue() + breakSign: func(m *sessiongrpc.SessionToken) { + cnr := m.GetBody().GetContext().(*sessiongrpc.SessionToken_Body_Object).Object.GetTarget().GetContainer().GetValue() cnr[len(cnr)-1]++ }, }, @@ -256,16 +257,16 @@ func TestObjectProtocolV2(t *testing.T) { require.NoError(t, val.Sign(signer), testcase.name) require.True(t, val.VerifySignature(), testcase.name) - var signedV2 v2session.Token + var signedV2 sessiongrpc.SessionToken val.WriteToV2(&signedV2) var restored session.Object - require.NoError(t, restored.ReadFromV2(signedV2), testcase.name) + require.NoError(t, restored.ReadFromV2(&signedV2), testcase.name) require.True(t, restored.VerifySignature(), testcase.name) testcase.breakSign(&signedV2) - require.NoError(t, restored.ReadFromV2(signedV2), testcase.name) + require.NoError(t, restored.ReadFromV2(&signedV2), testcase.name) require.False(t, restored.VerifySignature(), testcase.name) } } @@ -275,10 +276,10 @@ func TestObjectProtocolV2(t *testing.T) { func TestObject_WriteToV2(t *testing.T) { var val session.Object - assert := func(baseAssert func(v2session.Token)) { - var m v2session.Token + assert := func(baseAssert func(*sessiongrpc.SessionToken)) { + var m sessiongrpc.SessionToken val.WriteToV2(&m) - baseAssert(m) + baseAssert(&m) } // ID @@ -288,8 +289,8 @@ func TestObject_WriteToV2(t *testing.T) { require.NoError(t, err) val.SetID(id) - assert(func(m v2session.Token) { - require.Equal(t, binID, m.GetBody().GetID()) + assert(func(m *sessiongrpc.SessionToken) { + require.Equal(t, binID, m.GetBody().GetId()) }) // Owner/Signature @@ -300,11 +301,11 @@ func TestObject_WriteToV2(t *testing.T) { var usr user.ID user.IDFromKey(&usr, signer.PublicKey) - var usrV2 refs.OwnerID + var usrV2 refsgrpc.OwnerID usr.WriteToV2(&usrV2) - assert(func(m v2session.Token) { - require.Equal(t, &usrV2, m.GetBody().GetOwnerID()) + assert(func(m *sessiongrpc.SessionToken) { + require.Equal(t, &usrV2, m.GetBody().GetOwnerId()) sig := m.GetSignature() require.NotZero(t, sig.GetKey()) @@ -317,7 +318,7 @@ func TestObject_WriteToV2(t *testing.T) { val.SetNbf(nbf) val.SetExp(exp) - assert(func(m v2session.Token) { + assert(func(m *sessiongrpc.SessionToken) { lt := m.GetBody().GetLifetime() require.EqualValues(t, iat, lt.GetIat()) require.EqualValues(t, nbf, lt.GetNbf()) @@ -325,47 +326,48 @@ func TestObject_WriteToV2(t *testing.T) { }) // Context - assert(func(m v2session.Token) { - cCnr, ok := m.GetBody().GetContext().(*v2session.ObjectSessionContext) + assert(func(m *sessiongrpc.SessionToken) { + cCnr, ok := m.GetBody().GetContext().(*sessiongrpc.SessionToken_Body_Object) require.True(t, ok) - require.Zero(t, cCnr.GetContainer()) - require.Zero(t, cCnr.GetObjects()) + require.Zero(t, cCnr.Object.GetTarget().GetContainer()) + require.Zero(t, cCnr.Object.GetTarget().GetObjects()) }) cnr := cidtest.ID() - var cnrV2 refs.ContainerID + var cnrV2 refsgrpc.ContainerID cnr.WriteToV2(&cnrV2) obj1 := oidtest.ID() obj2 := oidtest.ID() - var obj1V2 refs.ObjectID + var obj1V2 refsgrpc.ObjectID obj1.WriteToV2(&obj1V2) - var obj2V2 refs.ObjectID + var obj2V2 refsgrpc.ObjectID obj2.WriteToV2(&obj2V2) val.BindContainer(cnr) val.LimitByObjects(obj1, obj2) - assert(func(m v2session.Token) { - cCnr, ok := m.GetBody().GetContext().(*v2session.ObjectSessionContext) + assert(func(m *sessiongrpc.SessionToken) { + cCnr, ok := m.GetBody().GetContext().(*sessiongrpc.SessionToken_Body_Object) require.True(t, ok) - require.Equal(t, &cnrV2, cCnr.GetContainer()) - require.Equal(t, []refs.ObjectID{obj1V2, obj2V2}, cCnr.GetObjects()) + require.Equal(t, &cnrV2, cCnr.Object.GetTarget().GetContainer()) + require.True(t, proto.Equal(&obj1V2, cCnr.Object.GetTarget().GetObjects()[0])) + require.True(t, proto.Equal(&obj2V2, cCnr.Object.GetTarget().GetObjects()[1])) }) } func TestObject_BindContainer(t *testing.T) { var val session.Object - var m v2session.Token + var m sessiongrpc.SessionToken filled := sessiontest.Object() assertDefaults := func() { - cCnr, ok := m.GetBody().GetContext().(*v2session.ObjectSessionContext) + cCnr, ok := m.GetBody().GetContext().(*sessiongrpc.SessionToken_Body_Object) require.True(t, ok) - require.Zero(t, cCnr.GetContainer()) - require.Zero(t, cCnr.GetObjects()) + require.Zero(t, cCnr.Object.GetTarget().GetContainer()) + require.Zero(t, cCnr.Object.GetTarget().GetObjects()) } assertBinary := func(baseAssert func()) { @@ -395,7 +397,7 @@ func TestObject_BindContainer(t *testing.T) { cnr := cidtest.ID() - var cnrV2 refs.ContainerID + var cnrV2 refsgrpc.ContainerID cnr.WriteToV2(&cnrV2) val.BindContainer(cnr) @@ -403,9 +405,9 @@ func TestObject_BindContainer(t *testing.T) { val.WriteToV2(&m) assertCnr := func() { - cObj, ok := m.GetBody().GetContext().(*v2session.ObjectSessionContext) + cObj, ok := m.GetBody().GetContext().(*sessiongrpc.SessionToken_Body_Object) require.True(t, ok) - require.Equal(t, &cnrV2, cObj.GetContainer()) + require.Equal(t, &cnrV2, cObj.Object.GetTarget().GetContainer()) } assertCnr() @@ -427,14 +429,14 @@ func TestObject_AssertContainer(t *testing.T) { func TestObject_LimitByObjects(t *testing.T) { var val session.Object - var m v2session.Token + var m sessiongrpc.SessionToken filled := sessiontest.Object() assertDefaults := func() { - cCnr, ok := m.GetBody().GetContext().(*v2session.ObjectSessionContext) + cCnr, ok := m.GetBody().GetContext().(*sessiongrpc.SessionToken_Body_Object) require.True(t, ok) - require.Zero(t, cCnr.GetContainer()) - require.Zero(t, cCnr.GetObjects()) + require.Zero(t, cCnr.Object.GetTarget().GetContainer()) + require.Zero(t, cCnr.Object.GetTarget().GetObjects()) } assertBinary := func(baseAssert func()) { @@ -465,9 +467,9 @@ func TestObject_LimitByObjects(t *testing.T) { obj1 := oidtest.ID() obj2 := oidtest.ID() - var obj1V2 refs.ObjectID + var obj1V2 refsgrpc.ObjectID obj1.WriteToV2(&obj1V2) - var obj2V2 refs.ObjectID + var obj2V2 refsgrpc.ObjectID obj2.WriteToV2(&obj2V2) val.LimitByObjects(obj1, obj2) @@ -475,9 +477,9 @@ func TestObject_LimitByObjects(t *testing.T) { val.WriteToV2(&m) assertObj := func() { - cObj, ok := m.GetBody().GetContext().(*v2session.ObjectSessionContext) + cObj, ok := m.GetBody().GetContext().(*sessiongrpc.SessionToken_Body_Object) require.True(t, ok) - require.Equal(t, []refs.ObjectID{obj1V2, obj2V2}, cObj.GetObjects()) + require.Equal(t, []*refsgrpc.ObjectID{&obj1V2, &obj2V2}, cObj.Object.GetTarget().GetObjects()) } assertObj() @@ -551,13 +553,13 @@ func TestObject_AssertAuthKey(t *testing.T) { func TestObject_ForVerb(t *testing.T) { var val session.Object - var m v2session.Token + var m sessiongrpc.SessionToken filled := sessiontest.Object() assertDefaults := func() { - cCnr, ok := m.GetBody().GetContext().(*v2session.ObjectSessionContext) + cCnr, ok := m.GetBody().GetContext().(*sessiongrpc.SessionToken_Body_Object) require.True(t, ok) - require.Zero(t, cCnr.GetVerb()) + require.Zero(t, cCnr.Object.GetVerb()) } assertBinary := func(baseAssert func()) { @@ -585,20 +587,20 @@ func TestObject_ForVerb(t *testing.T) { // set value - assertVerb := func(verb v2session.ObjectSessionVerb) { - cCnr, ok := m.GetBody().GetContext().(*v2session.ObjectSessionContext) + assertVerb := func(verb sessiongrpc.ObjectSessionContext_Verb) { + cCnr, ok := m.GetBody().GetContext().(*sessiongrpc.SessionToken_Body_Object) require.True(t, ok) - require.Equal(t, verb, cCnr.GetVerb()) + require.Equal(t, verb, cCnr.Object.GetVerb()) } - for from, to := range map[session.ObjectVerb]v2session.ObjectSessionVerb{ - session.VerbObjectPut: v2session.ObjectVerbPut, - session.VerbObjectGet: v2session.ObjectVerbGet, - session.VerbObjectHead: v2session.ObjectVerbHead, - session.VerbObjectSearch: v2session.ObjectVerbSearch, - session.VerbObjectRangeHash: v2session.ObjectVerbRangeHash, - session.VerbObjectRange: v2session.ObjectVerbRange, - session.VerbObjectDelete: v2session.ObjectVerbDelete, + for from, to := range map[session.ObjectVerb]sessiongrpc.ObjectSessionContext_Verb{ + session.VerbObjectPut: sessiongrpc.ObjectSessionContext_PUT, + session.VerbObjectGet: sessiongrpc.ObjectSessionContext_GET, + session.VerbObjectHead: sessiongrpc.ObjectSessionContext_HEAD, + session.VerbObjectSearch: sessiongrpc.ObjectSessionContext_SEARCH, + session.VerbObjectRangeHash: sessiongrpc.ObjectSessionContext_RANGEHASH, + session.VerbObjectRange: sessiongrpc.ObjectSessionContext_RANGE, + session.VerbObjectDelete: sessiongrpc.ObjectSessionContext_DELETE, } { val.ForVerb(from) diff --git a/session/test/session.go b/session/test/session.go index eef4e92..63432b3 100644 --- a/session/test/session.go +++ b/session/test/session.go @@ -28,7 +28,7 @@ func init() { // // Resulting token is unsigned. func Container() *session.Container { - var tok session.Container + tok := session.NewContainer() priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { @@ -64,7 +64,7 @@ func ContainerSigned() *session.Container { // // Resulting token is unsigned. func Object() *session.Object { - var tok session.Object + tok := session.NewObject() priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { @@ -80,7 +80,7 @@ func Object() *session.Object { tok.SetNbf(22) tok.SetIat(33) - return &tok + return tok } // ObjectSigned returns signed random session.Object. diff --git a/user/id.go b/user/id.go index b77492f..983eb18 100644 --- a/user/id.go +++ b/user/id.go @@ -5,7 +5,7 @@ import ( "errors" "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" "github.com/nspcc-dev/neo-go/pkg/crypto/hash" "github.com/nspcc-dev/neo-go/pkg/encoding/address" @@ -28,7 +28,7 @@ type ID struct { // the message is malformed according to the FrostFS API V2 protocol. // // See also WriteToV2. -func (x *ID) ReadFromV2(m refs.OwnerID) error { +func (x *ID) ReadFromV2(m *refs.OwnerID) error { w := m.GetValue() if len(w) != 25 { return fmt.Errorf("invalid length %d, expected 25", len(w)) @@ -52,6 +52,7 @@ func (x *ID) ReadFromV2(m refs.OwnerID) error { // // See also ReadFromV2. func (x ID) WriteToV2(m *refs.OwnerID) { + m.Reset() m.SetValue(x.w) } diff --git a/user/id_test.go b/user/id_test.go index 27d93dc..4083103 100644 --- a/user/id_test.go +++ b/user/id_test.go @@ -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" . "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user" usertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user/test" "github.com/mr-tron/base58" @@ -25,7 +25,7 @@ func TestID_WalletBytes(t *testing.T) { var m refs.OwnerID m.SetValue(w) - err := id.ReadFromV2(m) + err := id.ReadFromV2(&m) require.NoError(t, err) } @@ -41,7 +41,7 @@ func TestID_SetScriptHash(t *testing.T) { var id2 ID - err := id2.ReadFromV2(m) + err := id2.ReadFromV2(&m) require.NoError(t, err) require.True(t, id2.Equals(id)) @@ -55,7 +55,7 @@ func TestV2_ID(t *testing.T) { t.Run("OK", func(t *testing.T) { id.WriteToV2(&m) - err := id2.ReadFromV2(m) + err := id2.ReadFromV2(&m) require.NoError(t, err) require.True(t, id2.Equals(id)) }) @@ -65,7 +65,7 @@ func TestV2_ID(t *testing.T) { t.Run("invalid size", func(t *testing.T) { m.SetValue(val[:24]) - err := id2.ReadFromV2(m) + err := id2.ReadFromV2(&m) require.Error(t, err) }) @@ -75,7 +75,7 @@ func TestV2_ID(t *testing.T) { m.SetValue(val) - err := id2.ReadFromV2(m) + err := id2.ReadFromV2(&m) require.Error(t, err) }) @@ -85,7 +85,7 @@ func TestV2_ID(t *testing.T) { m.SetValue(val) - err := id2.ReadFromV2(m) + err := id2.ReadFromV2(&m) require.Error(t, err) }) } diff --git a/util/slices/slices.go b/util/slices/slices.go new file mode 100644 index 0000000..6c6cf47 --- /dev/null +++ b/util/slices/slices.go @@ -0,0 +1,18 @@ +package slices + +func MakePreallocPointerSlice[T any](sizes ...int) (res []*T) { + switch l := len(sizes); l { + case 0: + return res + case 1: + res = make([]*T, sizes[0]) + case 2: + res = make([]*T, sizes[0], sizes[1]) + default: + panic("unexpected number of params") + } + for i := range res { + res[i] = new(T) + } + return res +} diff --git a/version/doc.go b/version/doc.go index 8ade1a5..67b7337 100644 --- a/version/doc.go +++ b/version/doc.go @@ -11,7 +11,7 @@ version in SDK: It is possible to specify arbitrary version by setting major and minor numbers: - var ver version.Version + ver := version.NewVersion() ver.SetMajor(2) ver.SetMinor(5) */ diff --git a/version/test/generate.go b/version/test/generate.go index 75a02bf..99510b0 100644 --- a/version/test/generate.go +++ b/version/test/generate.go @@ -8,6 +8,7 @@ import ( // Version returns random version.Version. func Version() (v version.Version) { + v = version.NewVersion() v.SetMajor(rand.Uint32()) v.SetMinor(rand.Uint32()) return v diff --git a/version/version.go b/version/version.go index 47e61c8..bccd6eb 100644 --- a/version/version.go +++ b/version/version.go @@ -3,66 +3,83 @@ package version import ( "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" ) // Version represents revision number in SemVer scheme. // -// Version is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs.Version +// Version is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refsgrpc.Version // message. See ReadFromV2 / WriteToV2 methods. // -// Instances can be created using built-in var declaration. +// Instances must be created by NewVersion() constructor. // // Note that direct typecast is not safe and may result in loss of compatibility: // -// _ = Version(refs.Version{}) // not recommended -type Version refs.Version +// _ = Version(refsgrpc.Version{}) // not recommended +type Version struct { + version *refsgrpc.Version +} + +func NewVersion() Version { + return Version{ + version: &refsgrpc.Version{}, + } +} const sdkMjr, sdkMnr = 2, 13 // Current returns Version instance that initialized to the // latest supported FrostFS API revision number in SDK. func Current() (v Version) { + v = NewVersion() v.SetMajor(sdkMjr) v.SetMinor(sdkMnr) return v } // Major returns major number of the revision. -func (v *Version) Major() uint32 { - return (*refs.Version)(v).GetMajor() +func (v *Version) GetMajor() uint32 { + if v.version == nil { + return 0 + } + return v.version.GetMajor() } // SetMajor sets major number of the revision. func (v *Version) SetMajor(val uint32) { - (*refs.Version)(v).SetMajor(val) + v.version.Major = val } // Minor returns minor number of the revision. -func (v *Version) Minor() uint32 { - return (*refs.Version)(v).GetMinor() +func (v *Version) GetMinor() uint32 { + if v.version == nil { + return 0 + } + return v.version.GetMinor() } // SetMinor sets minor number of the revision. func (v *Version) SetMinor(val uint32) { - (*refs.Version)(v).SetMinor(val) + v.version.Minor = val } -// WriteToV2 writes Version to the refs.Version message. +// WriteToV2 writes Version to the refsgrpc.Version message. // The message must not be nil. // // See also ReadFromV2. -func (v Version) WriteToV2(m *refs.Version) { - *m = (refs.Version)(v) +func (v Version) WriteToV2(m *refsgrpc.Version) { + m.Reset() + proto.Merge(m, v.version) } -// ReadFromV2 reads Version from the refs.Version message. Checks if the message +// ReadFromV2 reads Version from the refsgrpc.Version message. Checks if the message // conforms to FrostFS API V2 protocol. // // See also WriteToV2. -func (v *Version) ReadFromV2(m refs.Version) error { - *v = Version(m) - return nil +func (v *Version) ReadFromV2(m *refsgrpc.Version) { + v.version.Reset() + proto.Merge(v.version, m) } // String implements fmt.Stringer. @@ -76,11 +93,11 @@ func (v Version) String() string { // EncodeToString encodes version according to format from specification: // semver formatted value without patch and with v prefix, e.g. 'v2.1'. func EncodeToString(v Version) string { - return fmt.Sprintf("v%d.%d", v.Major(), v.Minor()) + return fmt.Sprintf("v%d.%d", v.GetMajor(), v.GetMinor()) } // Equal returns true if versions are identical. func (v Version) Equal(v2 Version) bool { - return v.Major() == v2.Major() && - v.Minor() == v2.Minor() + return v.GetMajor() == v2.GetMajor() && + v.GetMinor() == v2.GetMinor() } diff --git a/version/version_test.go b/version/version_test.go index fdf2b6a..9e6e016 100644 --- a/version/version_test.go +++ b/version/version_test.go @@ -3,48 +3,54 @@ package version import ( "testing" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" + refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc" "github.com/stretchr/testify/require" ) func TestNewVersion(t *testing.T) { t.Run("default values", func(t *testing.T) { - var v Version + v := NewVersion() // check initial values - require.Zero(t, v.Major()) - require.Zero(t, v.Minor()) + require.Zero(t, v.GetMajor()) + require.Zero(t, v.GetMinor()) // convert to v2 message - var vV2 refs.Version - v.WriteToV2(&vV2) + v2 := new(refsgrpc.Version) + v.WriteToV2(v2) - require.Zero(t, vV2.GetMajor()) - require.Zero(t, vV2.GetMinor()) + require.Zero(t, v2.GetMajor()) + require.Zero(t, v2.GetMinor()) }) t.Run("setting values", func(t *testing.T) { - var v Version + v := NewVersion() var mjr, mnr uint32 = 1, 2 v.SetMajor(mjr) v.SetMinor(mnr) - require.Equal(t, mjr, v.Major()) - require.Equal(t, mnr, v.Minor()) + require.Equal(t, mjr, v.GetMajor()) + require.Equal(t, mnr, v.GetMinor()) // convert to v2 message - var ver refs.Version - v.WriteToV2(&ver) + ver := new(refsgrpc.Version) + v.WriteToV2(ver) require.Equal(t, mjr, ver.GetMajor()) require.Equal(t, mnr, ver.GetMinor()) + + v2 := NewVersion() + v2.ReadFromV2(ver) + + require.Equal(t, mjr, v2.GetMajor()) + require.Equal(t, mnr, v2.GetMinor()) }) } func TestSDKVersion(t *testing.T) { v := Current() - require.Equal(t, uint32(sdkMjr), v.Major()) - require.Equal(t, uint32(sdkMnr), v.Minor()) + require.Equal(t, uint32(sdkMjr), v.GetMajor()) + require.Equal(t, uint32(sdkMnr), v.GetMinor()) }