frostfs-sdk-go/eacl/filter.go
Airat Arifullin 6281a25556
All checks were successful
/ DCO (pull_request) Successful in 1m17s
/ Lint (pull_request) Successful in 2m7s
/ Tests (1.19) (pull_request) Successful in 5m56s
/ Tests (1.20) (pull_request) Successful in 6m37s
[#100] types: Make sdk types as protobuf wrappers
Signed-off-by: Airat Arifullin a.arifullin@yadro.com
2023-07-12 19:08:37 +03:00

216 lines
5 KiB
Go

package eacl
import (
"strconv"
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
// header means that request should be processed according to ContainerEACL action.
//
// Filter is compatible with v2 acl.EACLRecord.Filter message.
type Filter struct {
from FilterHeaderType
matcher Match
key filterKey
value stringEncoder
}
type staticStringer string
type u64Stringer uint64
type filterKey struct {
typ filterKeyType
str string
}
// enumeration of reserved filter keys.
type filterKeyType int
const (
_ filterKeyType = iota
fKeyObjVersion
fKeyObjID
fKeyObjContainerID
fKeyObjOwnerID
fKeyObjCreationEpoch
fKeyObjPayloadLength
fKeyObjPayloadHash
fKeyObjType
fKeyObjHomomorphicHash
fKeyObjLast // helper, used in tests
)
func (s staticStringer) EncodeToString() string {
return string(s)
}
func (u u64Stringer) EncodeToString() string {
return strconv.FormatUint(uint64(u), 10)
}
// Value returns filtered string value.
func (f Filter) Value() string {
return f.value.EncodeToString()
}
// Matcher returns filter Match type.
func (f Filter) Matcher() Match {
return f.matcher
}
// Key returns key to the filtered header.
func (f Filter) Key() string {
return f.key.String()
}
// From returns FilterHeaderType that defined which header will be filtered.
func (f Filter) From() FilterHeaderType {
return f.from
}
// ToV2 converts Filter to v2 acl.EACLRecord.Filter message.
//
// Nil Filter converts to nil.
func (f *Filter) ToV2() *aclgrpc.EACLRecord_Filter {
if f == nil {
return nil
}
filter := new(aclgrpc.EACLRecord_Filter)
filter.SetValue(f.value.EncodeToString())
filter.SetKey(f.key.String())
filter.SetMatchType(f.matcher.ToV2())
filter.SetHeader(f.from.ToV2())
return filter
}
func (k filterKey) String() string {
switch k.typ {
default:
return k.str
case fKeyObjVersion:
return acl.FilterObjectVersion
case fKeyObjID:
return acl.FilterObjectID
case fKeyObjContainerID:
return acl.FilterObjectContainerID
case fKeyObjOwnerID:
return acl.FilterObjectOwnerID
case fKeyObjCreationEpoch:
return acl.FilterObjectCreationEpoch
case fKeyObjPayloadLength:
return acl.FilterObjectPayloadLength
case fKeyObjPayloadHash:
return acl.FilterObjectPayloadHash
case fKeyObjType:
return acl.FilterObjectType
case fKeyObjHomomorphicHash:
return acl.FilterObjectHomomorphicHash
}
}
func (k *filterKey) fromString(s string) {
switch s {
default:
k.typ, k.str = 0, s
case acl.FilterObjectVersion:
k.typ, k.str = fKeyObjVersion, ""
case acl.FilterObjectID:
k.typ, k.str = fKeyObjID, ""
case acl.FilterObjectContainerID:
k.typ, k.str = fKeyObjContainerID, ""
case acl.FilterObjectOwnerID:
k.typ, k.str = fKeyObjOwnerID, ""
case acl.FilterObjectCreationEpoch:
k.typ, k.str = fKeyObjCreationEpoch, ""
case acl.FilterObjectPayloadLength:
k.typ, k.str = fKeyObjPayloadLength, ""
case acl.FilterObjectPayloadHash:
k.typ, k.str = fKeyObjPayloadHash, ""
case acl.FilterObjectType:
k.typ, k.str = fKeyObjType, ""
case acl.FilterObjectHomomorphicHash:
k.typ, k.str = fKeyObjHomomorphicHash, ""
}
}
// NewFilter creates, initializes and returns blank Filter instance.
//
// Defaults:
// - header type: HeaderTypeUnknown;
// - matcher: MatchUnknown;
// - key: "";
// - value: "".
func NewFilter() *Filter {
return NewFilterFromV2(new(aclgrpc.EACLRecord_Filter))
}
// NewFilterFromV2 converts v2 acl.EACLRecord.Filter message to Filter.
func NewFilterFromV2(filter *aclgrpc.EACLRecord_Filter) *Filter {
f := new(Filter)
if filter == nil {
return f
}
f.from = FilterHeaderTypeFromV2(filter.GetHeaderType())
f.matcher = MatchFromV2(filter.GetMatchType())
f.key.fromString(filter.GetKey())
f.value = staticStringer(filter.GetValue())
return f
}
// Marshal marshals Filter into a protobuf binary form.
func (f *Filter) Marshal() ([]byte, error) {
return f.ToV2().StableMarshal(nil), nil
}
// Unmarshal unmarshals protobuf binary representation of Filter.
func (f *Filter) Unmarshal(data []byte) error {
fV2 := new(aclgrpc.EACLRecord_Filter)
if err := proto.Unmarshal(data, fV2); err != nil {
return err
}
*f = *NewFilterFromV2(fV2)
return nil
}
// MarshalJSON encodes Filter to protobuf JSON format.
func (f *Filter) MarshalJSON() ([]byte, error) {
return protojson.MarshalOptions{
EmitUnpopulated: true,
}.Marshal(
f.ToV2(),
)
}
// UnmarshalJSON decodes Filter from protobuf JSON format.
func (f *Filter) UnmarshalJSON(data []byte) error {
fV2 := new(aclgrpc.EACLRecord_Filter)
if err := protojson.Unmarshal(data, fV2); err != nil {
return err
}
*f = *NewFilterFromV2(fV2)
return nil
}
// equalFilters compares Filter with each other.
func equalFilters(f1, f2 Filter) bool {
return f1.From() == f2.From() &&
f1.Matcher() == f2.Matcher() &&
f1.Key() == f2.Key() &&
f1.Value() == f2.Value()
}