diff --git a/v2/session/convert.go b/v2/session/convert.go index 7beb6ed..42101d3 100644 --- a/v2/session/convert.go +++ b/v2/session/convert.go @@ -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 +} diff --git a/v2/session/json.go b/v2/session/json.go index e296887..be7b9ac 100644 --- a/v2/session/json.go +++ b/v2/session/json.go @@ -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)) +} diff --git a/v2/session/marshal.go b/v2/session/marshal.go index b6ea2c0..05085d7 100644 --- a/v2/session/marshal.go +++ b/v2/session/marshal.go @@ -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") } diff --git a/v2/session/message_test.go b/v2/session/message_test.go index ea9f1cc..17c428e 100644 --- a/v2/session/message_test.go +++ b/v2/session/message_test.go @@ -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) }, ) } diff --git a/v2/session/test/generate.go b/v2/session/test/generate.go index d1a5b56..bad4124 100644 --- a/v2/session/test/generate.go +++ b/v2/session/test/generate.go @@ -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) diff --git a/v2/session/types.go b/v2/session/types.go index 68c3a10..8d092a2 100644 --- a/v2/session/types.go +++ b/v2/session/types.go @@ -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 + } +}