forked from TrueCloudLab/policy-engine
258 lines
6.1 KiB
Go
258 lines
6.1 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.StringSize(string(c.ID))
|
||
|
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.StringMarshal(buf, offset, string(c.ID))
|
||
|
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)
|
||
|
}
|
||
|
|
||
|
idStr, offset, err := marshal.StringUnmarshal(data, offset)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
c.ID = ID(idStr)
|
||
|
|
||
|
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
|
||
|
}
|