[#283] v2/session: Support ContainerSessionContext message

Define `ContainerSessionContext` structure, implement getters / setters,
JSON and binary encoders, gRPC converters. Support new type of context in
SessionTokenBody message. Add test message generator and cover methods with
unit tests.

Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
support/v2.15
Leonard Lyubich 2021-05-24 17:46:39 +03:00 committed by Alex Vanin
parent f2be7509d3
commit 9eb567a53a
6 changed files with 261 additions and 0 deletions

View File

@ -707,6 +707,8 @@ func (t *SessionTokenBody) ToGRPCMessage() grpc.Message {
m.Context = nil
case *ObjectSessionContext:
m.SetObjectSessionContext(typ.ToGRPCMessage().(*session.ObjectSessionContext))
case *ContainerSessionContext:
m.SetContainerSessionContext(typ.ToGRPCMessage().(*session.ContainerSessionContext))
}
m.SetOwnerId(t.ownerID.ToGRPCMessage().(*refsGRPC.OwnerID))
@ -740,6 +742,14 @@ func (t *SessionTokenBody) FromGRPCMessage(m grpc.Message) error {
}
err = ctx.FromGRPCMessage(val.Object)
case *session.SessionToken_Body_Container:
ctx, ok := t.ctx.(*ContainerSessionContext)
if !ok {
ctx = new(ContainerSessionContext)
t.ctx = ctx
}
err = ctx.FromGRPCMessage(val.Container)
}
if err != nil {
@ -779,3 +789,87 @@ func (t *SessionTokenBody) FromGRPCMessage(m grpc.Message) error {
return nil
}
// ContainerSessionVerbToGRPCField converts ContainerSessionVerb
// to gRPC-generated session.ContainerSessionContext_Verb.
//
// If v is outside of the ContainerSessionVerb enum,
// session.ContainerSessionContext_VERB_UNSPECIFIED is returned.
func ContainerSessionVerbToGRPCField(v ContainerSessionVerb) session.ContainerSessionContext_Verb {
switch v {
default:
return session.ContainerSessionContext_VERB_UNSPECIFIED
case ContainerVerbPut:
return session.ContainerSessionContext_PUT
case ContainerVerbDelete:
return session.ContainerSessionContext_DELETE
case ContainerVerbSetEACL:
return session.ContainerSessionContext_SETEACL
}
}
// ContainerSessionVerbFromGRPCField converts gRPC-generated
// session.ContainerSessionContext_Verb to ContainerSessionVerb.
//
// If v is outside of the session.ContainerSessionContext_Verb enum,
// ContainerVerbUnknown is returned.
func ContainerSessionVerbFromGRPCField(v session.ContainerSessionContext_Verb) ContainerSessionVerb {
switch v {
default:
return ContainerVerbUnknown
case session.ContainerSessionContext_PUT:
return ContainerVerbPut
case session.ContainerSessionContext_DELETE:
return ContainerVerbDelete
case session.ContainerSessionContext_SETEACL:
return ContainerVerbSetEACL
}
}
// ToGRPCMessage converts ContainerSessionContext to gRPC-generated
// session.ContainerSessionContext message.
func (x *ContainerSessionContext) ToGRPCMessage() grpc.Message {
var m *session.ContainerSessionContext
if x != nil {
m = new(session.ContainerSessionContext)
m.SetVerb(ContainerSessionVerbToGRPCField(x.verb))
m.SetWildcard(x.wildcard)
m.SetContainerId(x.cid.ToGRPCMessage().(*refsGRPC.ContainerID))
}
return m
}
// FromGRPCMessage tries to restore ContainerSessionContext from grpc.Message.
//
// Returns message.ErrUnexpectedMessageType if m is not
// a gRPC-generated session.ContainerSessionContext message.
func (x *ContainerSessionContext) FromGRPCMessage(m grpc.Message) error {
v, ok := m.(*session.ContainerSessionContext)
if !ok {
return message.NewUnexpectedMessageType(m, v)
}
var err error
cid := v.GetContainerId()
if cid == nil {
x.cid = nil
} else {
if x.cid == nil {
x.cid = new(refs.ContainerID)
}
err = x.cid.FromGRPCMessage(cid)
if err != nil {
return err
}
}
x.verb = ContainerSessionVerbFromGRPCField(v.GetVerb())
x.wildcard = v.GetWildcard()
return nil
}

View File

@ -119,3 +119,11 @@ func (r *ResponseVerificationHeader) UnmarshalJSON(data []byte) error {
return r.FromGRPCMessage(msg)
}
func (x *ContainerSessionContext) MarshalJSON() ([]byte, error) {
return message.MarshalJSON(x)
}
func (x *ContainerSessionContext) UnmarshalJSON(data []byte) error {
return message.UnmarshalJSON(x, data, new(session.ContainerSessionContext))
}

View File

@ -29,6 +29,7 @@ const (
sessionTokenBodyLifetimeField = 3
sessionTokenBodyKeyField = 4
sessionTokenBodyObjectCtxField = 5
sessionTokenBodyCnrCtxField = 6
sessionTokenBodyField = 1
sessionTokenSignatureField = 2
@ -301,6 +302,65 @@ func (c *ObjectSessionContext) Unmarshal(data []byte) error {
return c.FromGRPCMessage(m)
}
const (
_ = iota
cnrCtxVerbFNum
cnrCtxWildcardFNum
cnrCtxCidFNum
)
func (x *ContainerSessionContext) StableMarshal(buf []byte) ([]byte, error) {
if x == nil {
return []byte{}, nil
}
if buf == nil {
buf = make([]byte, x.StableSize())
}
var (
offset, n int
err error
)
n, err = proto.EnumMarshal(cnrCtxVerbFNum, buf[offset:], int32(ContainerSessionVerbToGRPCField(x.verb)))
if err != nil {
return nil, err
}
offset += n
n, err = proto.BoolMarshal(cnrCtxWildcardFNum, buf[offset:], x.wildcard)
if err != nil {
return nil, err
}
offset += n
_, err = proto.NestedStructureMarshal(cnrCtxCidFNum, buf[offset:], x.cid)
if err != nil {
return nil, err
}
return buf, nil
}
func (x *ContainerSessionContext) StableSize() (size int) {
if x == nil {
return 0
}
size += proto.EnumSize(cnrCtxVerbFNum, int32(ContainerSessionVerbToGRPCField(x.verb)))
size += proto.BoolSize(cnrCtxWildcardFNum, x.wildcard)
size += proto.NestedStructureSize(cnrCtxCidFNum, x.cid)
return size
}
func (x *ContainerSessionContext) Unmarshal(data []byte) error {
return message.Unmarshal(x, data, new(session.ContainerSessionContext))
}
func (t *SessionTokenBody) StableMarshal(buf []byte) ([]byte, error) {
if t == nil {
return []byte{}, nil
@ -350,6 +410,11 @@ func (t *SessionTokenBody) StableMarshal(buf []byte) ([]byte, error) {
if err != nil {
return nil, err
}
case *ContainerSessionContext:
_, err = proto.NestedStructureMarshal(sessionTokenBodyCnrCtxField, buf[offset:], v)
if err != nil {
return nil, err
}
default:
panic("cannot marshal unknown session token context")
}
@ -372,6 +437,8 @@ func (t *SessionTokenBody) StableSize() (size int) {
switch v := t.ctx.(type) {
case *ObjectSessionContext:
size += proto.NestedStructureSize(sessionTokenBodyObjectCtxField, v)
case *ContainerSessionContext:
size += proto.NestedStructureSize(sessionTokenBodyCnrCtxField, v)
default:
panic("cannot marshal unknown session token context")
}

View File

@ -22,5 +22,6 @@ func TestMessageConvert(t *testing.T) {
func(empty bool) message.Message { return sessiontest.GenerateRequestVerificationHeader(empty) },
func(empty bool) message.Message { return sessiontest.GenerateResponseMetaHeader(empty) },
func(empty bool) message.Message { return sessiontest.GenerateResponseVerificationHeader(empty) },
func(empty bool) message.Message { return sessiontest.GenerateContainerSessionContext(empty) },
)
}

View File

@ -179,6 +179,19 @@ func GenerateObjectSessionContext(empty bool) *session.ObjectSessionContext {
return m
}
func GenerateContainerSessionContext(empty bool) *session.ContainerSessionContext {
m := new(session.ContainerSessionContext)
if !empty {
m.SetVerb(session.ContainerVerbDelete)
m.SetWildcard(true)
}
m.SetContainerID(refstest.GenerateContainerID(empty))
return m
}
func GenerateXHeader(empty bool) *session.XHeader {
m := new(session.XHeader)

View File

@ -735,3 +735,81 @@ func (t *SessionToken) SetSignature(v *refs.Signature) {
t.sig = v
}
}
// ContainerSessionVerb represents NeoFS API v2
// session.ContainerSessionContext.Verb enumeration.
type ContainerSessionVerb uint32
const (
// ContainerVerbUnknown corresponds to VERB_UNSPECIFIED enum value.
ContainerVerbUnknown ContainerSessionVerb = iota
// ContainerVerbPut corresponds to PUT enum value.
ContainerVerbPut
// ContainerVerbDelete corresponds to DELETE enum value.
ContainerVerbDelete
// ContainerVerbSetEACL corresponds to SETEACL enum value.
ContainerVerbSetEACL
)
// ContainerSessionContext represents structure of the
// NeoFS API v2 session.ContainerSessionContext message.
type ContainerSessionContext struct {
verb ContainerSessionVerb
wildcard bool
cid *refs.ContainerID
}
func (x *ContainerSessionContext) sessionTokenContext() {}
// Verb returns type of request for which the token is issued.
func (x *ContainerSessionContext) Verb() ContainerSessionVerb {
if x != nil {
return x.verb
}
return ContainerVerbUnknown
}
// SetVerb sets type of request for which the token is issued.
func (x *ContainerSessionContext) SetVerb(v ContainerSessionVerb) {
if x != nil {
x.verb = v
}
}
// Wildcard returns wildcard flag of the container session.
func (x *ContainerSessionContext) Wildcard() bool {
if x != nil {
return x.wildcard
}
return false
}
// SetWildcard sets wildcard flag of the container session.
func (x *ContainerSessionContext) SetWildcard(v bool) {
if x != nil {
x.wildcard = v
}
}
// ContainerID returns identifier of the container related to the session.
func (x *ContainerSessionContext) ContainerID() *refs.ContainerID {
if x != nil {
return x.cid
}
return nil
}
// SetContainerID sets identifier of the container related to the session.
func (x *ContainerSessionContext) SetContainerID(v *refs.ContainerID) {
if x != nil {
x.cid = v
}
}