forked from TrueCloudLab/policy-engine
Dmitrii Stepanov
dd0f582fc3
ID may be non UTF-8 string, so from developers POV it is just byte slice. Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
257 lines
6.2 KiB
Go
257 lines
6.2 KiB
Go
package chain
|
|
|
|
import (
|
|
"encoding"
|
|
"fmt"
|
|
|
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/marshal"
|
|
)
|
|
|
|
const (
|
|
ChainMarshalVersion uint8 = 0 // increase if breaking change
|
|
)
|
|
|
|
var (
|
|
_ encoding.BinaryMarshaler = (*Chain)(nil)
|
|
_ encoding.BinaryUnmarshaler = (*Chain)(nil)
|
|
)
|
|
|
|
func (c *Chain) MarshalBinary() ([]byte, error) {
|
|
s := marshal.UInt8Size // Marshaller version
|
|
s += marshal.UInt8Size // Chain version
|
|
s += marshal.SliceSize(c.ID, func(byte) int { return marshal.ByteSize })
|
|
s += marshal.SliceSize(c.Rules, ruleSize)
|
|
s += marshal.UInt8Size // MatchType
|
|
|
|
buf := make([]byte, s)
|
|
var offset int
|
|
var err error
|
|
offset, err = marshal.UInt8Marshal(buf, offset, marshal.Version)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
offset, err = marshal.UInt8Marshal(buf, offset, ChainMarshalVersion)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
offset, err = marshal.SliceMarshal(buf, offset, c.ID, marshal.ByteMarshal)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
offset, err = marshal.SliceMarshal(buf, offset, c.Rules, marshalRule)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
offset, err = marshal.UInt8Marshal(buf, offset, uint8(c.MatchType))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := marshal.VerifyMarshal(buf, offset); err != nil {
|
|
return nil, err
|
|
}
|
|
return buf, nil
|
|
}
|
|
|
|
func (c *Chain) UnmarshalBinary(data []byte) error {
|
|
var offset int
|
|
|
|
marshallerVersion, offset, err := marshal.UInt8Unmarshal(data, offset)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if marshallerVersion != marshal.Version {
|
|
return fmt.Errorf("unsupported marshaller version %d", marshallerVersion)
|
|
}
|
|
|
|
chainVersion, offset, err := marshal.UInt8Unmarshal(data, offset)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if chainVersion != ChainMarshalVersion {
|
|
return fmt.Errorf("unsupported chain version %d", chainVersion)
|
|
}
|
|
|
|
idBytes, offset, err := marshal.SliceUnmarshal(data, offset, marshal.ByteUnmarshal)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
c.ID = ID(idBytes)
|
|
|
|
c.Rules, offset, err = marshal.SliceUnmarshal(data, offset, unmarshalRule)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
matchTypeV, offset, err := marshal.UInt8Unmarshal(data, offset)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
c.MatchType = MatchType(matchTypeV)
|
|
|
|
return marshal.VerifyUnmarshal(data, offset)
|
|
}
|
|
|
|
func ruleSize(r Rule) int {
|
|
s := marshal.ByteSize // Status
|
|
s += actionsSize(r.Actions)
|
|
s += resourcesSize(r.Resources)
|
|
s += marshal.BoolSize // Any
|
|
s += marshal.SliceSize(r.Condition, conditionSize)
|
|
return s
|
|
}
|
|
|
|
func marshalRule(buf []byte, offset int, r Rule) (int, error) {
|
|
offset, err := marshal.ByteMarshal(buf, offset, byte(r.Status))
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
offset, err = marshalActions(buf, offset, r.Actions)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
offset, err = marshalResources(buf, offset, r.Resources)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
offset, err = marshal.BoolMarshal(buf, offset, r.Any)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return marshal.SliceMarshal(buf, offset, r.Condition, marshalCondition)
|
|
}
|
|
|
|
func unmarshalRule(buf []byte, offset int) (Rule, int, error) {
|
|
var r Rule
|
|
statusV, offset, err := marshal.ByteUnmarshal(buf, offset)
|
|
if err != nil {
|
|
return Rule{}, 0, err
|
|
}
|
|
r.Status = Status(statusV)
|
|
|
|
r.Actions, offset, err = unmarshalActions(buf, offset)
|
|
if err != nil {
|
|
return Rule{}, 0, err
|
|
}
|
|
|
|
r.Resources, offset, err = unmarshalResources(buf, offset)
|
|
if err != nil {
|
|
return Rule{}, 0, err
|
|
}
|
|
|
|
r.Any, offset, err = marshal.BoolUnmarshal(buf, offset)
|
|
if err != nil {
|
|
return Rule{}, 0, err
|
|
}
|
|
|
|
r.Condition, offset, err = marshal.SliceUnmarshal(buf, offset, unmarshalCondition)
|
|
if err != nil {
|
|
return Rule{}, 0, err
|
|
}
|
|
|
|
return r, offset, nil
|
|
}
|
|
|
|
func actionsSize(a Actions) int {
|
|
return marshal.BoolSize + // Inverted
|
|
marshal.SliceSize(a.Names, marshal.StringSize)
|
|
}
|
|
|
|
func marshalActions(buf []byte, offset int, a Actions) (int, error) {
|
|
offset, err := marshal.BoolMarshal(buf, offset, a.Inverted)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return marshal.SliceMarshal(buf, offset, a.Names, marshal.StringMarshal)
|
|
}
|
|
|
|
func unmarshalActions(buf []byte, offset int) (Actions, int, error) {
|
|
var a Actions
|
|
var err error
|
|
a.Inverted, offset, err = marshal.BoolUnmarshal(buf, offset)
|
|
if err != nil {
|
|
return Actions{}, 0, err
|
|
}
|
|
a.Names, offset, err = marshal.SliceUnmarshal(buf, offset, marshal.StringUnmarshal)
|
|
if err != nil {
|
|
return Actions{}, 0, err
|
|
}
|
|
return a, offset, nil
|
|
}
|
|
|
|
func resourcesSize(r Resources) int {
|
|
return marshal.BoolSize + // Inverted
|
|
marshal.SliceSize(r.Names, marshal.StringSize)
|
|
}
|
|
|
|
func marshalResources(buf []byte, offset int, r Resources) (int, error) {
|
|
offset, err := marshal.BoolMarshal(buf, offset, r.Inverted)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return marshal.SliceMarshal(buf, offset, r.Names, marshal.StringMarshal)
|
|
}
|
|
|
|
func unmarshalResources(buf []byte, offset int) (Resources, int, error) {
|
|
var r Resources
|
|
var err error
|
|
r.Inverted, offset, err = marshal.BoolUnmarshal(buf, offset)
|
|
if err != nil {
|
|
return Resources{}, 0, err
|
|
}
|
|
r.Names, offset, err = marshal.SliceUnmarshal(buf, offset, marshal.StringUnmarshal)
|
|
if err != nil {
|
|
return Resources{}, 0, err
|
|
}
|
|
return r, offset, nil
|
|
}
|
|
|
|
func conditionSize(c Condition) int {
|
|
return marshal.ByteSize + // Op
|
|
marshal.ByteSize + // Object
|
|
marshal.StringSize(c.Key) +
|
|
marshal.StringSize(c.Value)
|
|
}
|
|
|
|
func marshalCondition(buf []byte, offset int, c Condition) (int, error) {
|
|
offset, err := marshal.ByteMarshal(buf, offset, byte(c.Op))
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
offset, err = marshal.ByteMarshal(buf, offset, byte(c.Object))
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
offset, err = marshal.StringMarshal(buf, offset, c.Key)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return marshal.StringMarshal(buf, offset, c.Value)
|
|
}
|
|
|
|
func unmarshalCondition(buf []byte, offset int) (Condition, int, error) {
|
|
var c Condition
|
|
opV, offset, err := marshal.ByteUnmarshal(buf, offset)
|
|
if err != nil {
|
|
return Condition{}, 0, err
|
|
}
|
|
c.Op = ConditionType(opV)
|
|
|
|
obV, offset, err := marshal.ByteUnmarshal(buf, offset)
|
|
if err != nil {
|
|
return Condition{}, 0, err
|
|
}
|
|
c.Object = ObjectType(obV)
|
|
|
|
c.Key, offset, err = marshal.StringUnmarshal(buf, offset)
|
|
if err != nil {
|
|
return Condition{}, 0, err
|
|
}
|
|
|
|
c.Value, offset, err = marshal.StringUnmarshal(buf, offset)
|
|
if err != nil {
|
|
return Condition{}, 0, err
|
|
}
|
|
|
|
return c, offset, nil
|
|
}
|