diff --git a/context.go b/context.go index 776cfa5..5491bcc 100644 --- a/context.go +++ b/context.go @@ -1,92 +1,19 @@ package graphvent import ( - "crypto/ecdh" - "crypto/sha512" - "encoding/binary" - "errors" - "fmt" - "math" - "reflect" - "runtime" - "sync" - "strconv" - - badger "github.com/dgraph-io/badger/v3" -) - -func Hash(base string, name string) uint64 { - digest := append([]byte(base), 0x00) - digest = append(digest, []byte(name)...) - hash := sha512.Sum512(digest) - return binary.BigEndian.Uint64(hash[0:8]) -} - -type ExtType uint64 -type NodeType uint64 -type SignalType uint64 -type PolicyType uint64 -type SerializedType uint64 - -func NewExtType(name string) ExtType { - return ExtType(Hash(ExtTypeBase, name)) -} - -func NewNodeType(name string) NodeType { - return NodeType(Hash(NodeTypeBase, name)) -} - -func NewSignalType(name string) SignalType { - return SignalType(Hash(SignalTypeBase, name)) -} - -func NewPolicyType(name string) PolicyType { - return PolicyType(Hash(PolicyTypeBase, name)) -} - -func NewSerializedType(name string) SerializedType { - val := SerializedType(Hash(SerializedTypeBase, name)) - println(fmt.Sprintf("TYPE: %s: %d", name, val)) - return val -} - -const ( - TagBase = "GraphventTag" - ExtTypeBase = "ExtType" - NodeTypeBase = "NodeType" - SignalTypeBase = "SignalType" - PolicyTypeBase = "PolicyType" - SerializedTypeBase = "SerializedType" - FieldNameBase = "FieldName" + "crypto/ecdh" + "encoding/binary" + "errors" + "fmt" + "math" + "reflect" + "runtime" + "sync" + + badger "github.com/dgraph-io/badger/v3" ) var ( - ListenerExtType = NewExtType("LISTENER") - LockableExtType = NewExtType("LOCKABLE") - GQLExtType = NewExtType("GQL") - GroupExtType = NewExtType("GROUP") - ECDHExtType = NewExtType("ECDH") - - GQLNodeType = NewNodeType("GQL") - - StopSignalType = NewSignalType("STOP") - CreateSignalType = NewSignalType("CREATE") - StartSignalType = NewSignalType("START") - ErrorSignalType = NewSignalType("ERROR") - StatusSignalType = NewSignalType("STATUS") - LinkSignalType = NewSignalType("LINK") - LockSignalType = NewSignalType("LOCK") - ReadSignalType = NewSignalType("READ") - ReadResultSignalType = NewSignalType("READ_RESULT") - ACLTimeoutSignalType = NewSignalType("ACL_TIMEOUT") - - MemberOfPolicyType = NewPolicyType("USER_OF") - RequirementOfPolicyType = NewPolicyType("REQUIEMENT_OF") - PerNodePolicyType = NewPolicyType("PER_NODE") - AllNodesPolicyType = NewPolicyType("ALL_NODES") - - ErrorType = NewSerializedType("ERROR") - NodeNotFoundError = errors.New("Node not found in DB") ECDH = ecdh.X25519() ) @@ -100,14 +27,18 @@ type NodeInfo struct { Extensions []ExtType } -type TypeSerialize func(*Context,uint64,reflect.Type,*reflect.Value) (SerializedValue, error) -type TypeDeserialize func(*Context,SerializedValue) (reflect.Type, *reflect.Value, SerializedValue, error) type TypeInfo struct { Type reflect.Type Serialize TypeSerialize Deserialize TypeDeserialize } +type KindInfo struct { + Type SerializedType + Serialize TypeSerialize + Deserialize TypeDeserialize +} + // A Context stores all the data to run a graphvent process type Context struct { // DB is the database connection used to load and write nodes @@ -309,149 +240,6 @@ func (ctx *Context) Send(messages Messages) error { return nil } -type KindInfo struct { - Type SerializedType - Serialize TypeSerialize - Deserialize TypeDeserialize -} - -type SerializedValue struct { - TypeStack []uint64 - Data []byte -} - -func SerializeValue(ctx *Context, value reflect.Value) (SerializedValue, error) { - val, err := serializeValue(ctx, value.Type(), &value) - ctx.Log.Logf("serialize", "SERIALIZED_VALUE(%+v): %+v - %+v", value.Type(), val.TypeStack, val.Data) - return val, err -} - -func serializeValue(ctx *Context, t reflect.Type, value *reflect.Value) (SerializedValue, error) { - var ctx_type uint64 = 0x00 - ctype, exists := ctx.TypeReflects[t] - if exists == true { - type_info := ctx.Types[ctype] - ctx_type = uint64(ctype) - if type_info.Serialize != nil { - return type_info.Serialize(ctx, ctx_type, t, value) - } - } - - kind := t.Kind() - kind_info, handled := ctx.Kinds[kind] - if handled == false { - return SerializedValue{}, fmt.Errorf("Don't know how to serialize kind %+v", kind) - } else if ctx_type == 0x00 { - ctx_type = uint64(kind_info.Type) - } - - return kind_info.Serialize(ctx, ctx_type, t, value) - -} - -func SerializeField(ctx *Context, ext Extension, field_name string) (SerializedValue, error) { - if ext == nil { - return SerializedValue{}, fmt.Errorf("Cannot get fields on nil Extension") - } - ext_value := reflect.ValueOf(ext).Elem() - field := ext_value.FieldByName(field_name) - if field.IsValid() == false { - return SerializedValue{}, fmt.Errorf("%s is not a field in %+v", field_name, ext) - } else { - return SerializeValue(ctx, field) - } -} - -func (value SerializedValue) MarshalBinary() ([]byte, error) { - data := make([]byte, value.SerializedSize()) - binary.BigEndian.PutUint64(data[0:8], uint64(len(value.TypeStack))) - binary.BigEndian.PutUint64(data[8:16], uint64(len(value.Data))) - - for i, t := range(value.TypeStack) { - type_start := (i+2)*8 - type_end := (i+3)*8 - binary.BigEndian.PutUint64(data[type_start:type_end], t) - } - - return append(data, value.Data...), nil -} - -func (value SerializedValue) SerializedSize() uint64 { - return uint64((len(value.TypeStack) + 2) * 8) -} - -func ParseSerializedValue(data []byte) (SerializedValue, []byte, error) { - if len(data) < 8 { - return SerializedValue{}, nil, fmt.Errorf("SerializedValue required to have at least 8 bytes when serialized") - } - num_types := int(binary.BigEndian.Uint64(data[0:8])) - data_size := int(binary.BigEndian.Uint64(data[8:16])) - type_stack := make([]uint64, num_types) - for i := 0; i < num_types; i += 1 { - type_start := (i+2) * 8 - type_end := (i+3) * 8 - type_stack[i] = binary.BigEndian.Uint64(data[type_start:type_end]) - } - - types_end := 8*(num_types + 2) - data_end := types_end + data_size - return SerializedValue{ - type_stack, - data[types_end:data_end], - }, data[data_end:], nil -} - -func DeserializeValue(ctx *Context, value SerializedValue, n int) (reflect.Type, []reflect.Value, SerializedValue, error) { - ctx.Log.Logf("serialize", "DeserializeValue: %+v - %d", value, n) - ret := make([]reflect.Value, n) - - var deserialize TypeDeserialize = nil - var reflect_type reflect.Type = nil - - ctx_type := value.TypeStack[0] - value.TypeStack = value.TypeStack[1:] - - type_info, exists := ctx.Types[SerializedType(ctx_type)] - if exists == true { - deserialize = type_info.Deserialize - reflect_type = type_info.Type - } else { - kind, exists := ctx.KindTypes[SerializedType(ctx_type)] - if exists == false { - return nil, nil, SerializedValue{}, fmt.Errorf("Cannot deserialize 0x%x: unknown type/kind", ctx_type) - } - kind_info := ctx.Kinds[kind] - deserialize = kind_info.Deserialize - } - - ctx.Log.Logf("serialize", "Deserializing: %d x %d", ctx_type, n) - - if value.Data == nil { - reflect_type, _, val, err := deserialize(ctx, value) - if err != nil { - return nil, nil, SerializedValue{}, err - } - return reflect_type, nil, val, nil - } - - val := SerializedValue{ - value.TypeStack, - value.Data, - } - for i := 0; i < n; i += 1 { - val.TypeStack = value.TypeStack - var elem *reflect.Value - var err error - reflect_type, elem, val, err = deserialize(ctx, val) - if err != nil { - return nil, nil, SerializedValue{}, err - } - ret[i] = *elem - } - ctx.Log.Logf("serialize", "DeserializeValue: DONE %+v - %+v", val, ret) - return reflect_type, ret, val, nil -} - // Create a new Context with the base library content added func NewContext(db * badger.DB, log Logger) (*Context, error) { ctx := &Context{ @@ -473,32 +261,32 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { var err error err = ctx.RegisterKind(reflect.Pointer, NewSerializedType("pointer"), - func(ctx *Context, ctx_type uint64, reflect_type reflect.Type, value *reflect.Value) (SerializedValue, error) { - var data []byte - var elem_value *reflect.Value = nil - if value == nil { - data = nil - } else if value.IsZero() { - data = []byte{0x01} - } else { - data = []byte{0x00} - ev := value.Elem() - elem_value = &ev - } - elem, err := serializeValue(ctx, reflect_type.Elem(), elem_value) - if err != nil { - return SerializedValue{}, err - } - if elem.Data != nil { - data = append(data, elem.Data...) - } - return SerializedValue{ - append([]uint64{ctx_type}, elem.TypeStack...), - data, - }, nil + func(ctx *Context, ctx_type SerializedType, reflect_type reflect.Type, value *reflect.Value) (SerializedValue, error) { + var data []byte + var elem_value *reflect.Value = nil + if value == nil { + data = nil + } else if value.IsZero() { + data = []byte{0x01} + } else { + data = []byte{0x00} + ev := value.Elem() + elem_value = &ev + } + elem, err := serializeValue(ctx, reflect_type.Elem(), elem_value) + if err != nil { + return SerializedValue{}, err + } + if elem.Data != nil { + data = append(data, elem.Data...) + } + return SerializedValue{ + append([]SerializedType{ctx_type}, elem.TypeStack...), + data, + }, nil }, func(ctx *Context, value SerializedValue) (reflect.Type, *reflect.Value, SerializedValue, error) { if value.Data == nil { - elem_type, _, _, err := DeserializeValue(ctx, value, 1) + elem_type, _, _, err := DeserializeValue(ctx, value) if err != nil { return nil, nil, SerializedValue{}, err } @@ -509,14 +297,14 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { pointer_flags := value.Data[0] value.Data = value.Data[1:] if pointer_flags == 0x00 { - _, elem_value, remaining_data, err := DeserializeValue(ctx, value, 1) + _, elem_value, remaining_data, err := DeserializeValue(ctx, value) if err != nil { return nil, nil, SerializedValue{}, err } - pointer_value := elem_value[0].Addr() + pointer_value := elem_value.Addr() return pointer_value.Type(), &pointer_value, remaining_data, nil } else if pointer_flags == 0x01 { - elem_type, _, remaining_data, err := DeserializeValue(ctx, value, 1) + elem_type, _, remaining_data, err := DeserializeValue(ctx, value) if err != nil { return nil, nil, SerializedValue{}, err } @@ -534,14 +322,12 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { } err = ctx.RegisterKind(reflect.Struct, NewSerializedType("struct"), - func(ctx *Context, ctx_type uint64, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ - // TODO: Switch from serializing each field as a []byte of a SerializedValue.MarshalBinary to just running serializeValue and adding the TypeStack and Data together + func(ctx *Context, ctx_type SerializedType, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ serialized_value := SerializedValue{ - []uint64{ctx_type}, + []SerializedType{ctx_type}, nil, } - num_fields := 0 - field_values := map[int]SerializedValue{} + field_values := map[SerializedType]SerializedValue{} for _, field := range(reflect.VisibleFields(reflect_type)) { gv_tag, tagged_gv := field.Tag.Lookup("gv") if tagged_gv == false { @@ -550,39 +336,24 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { continue } else { // Add to the type stack and data stack - field_index, err := strconv.Atoi(gv_tag) - if err != nil { - return SerializedValue{}, err - } - num_fields += 1 + field_hash := Hash(FieldNameBase, gv_tag) if value == nil { field_ser, err := serializeValue(ctx, field.Type, nil) if err != nil { return SerializedValue{}, err } - field_values[field_index] = field_ser + field_values[field_hash] = field_ser } else { field_value := value.FieldByIndex(field.Index) field_ser, err := serializeValue(ctx, field.Type, &field_value) if err != nil { return SerializedValue{}, err } - field_values[field_index] = field_ser + field_values[field_hash] = field_ser } } } - for i := 0; i < num_fields; i += 1 { - field_value, exists := field_values[i] - if exists == false { - return SerializedValue{}, fmt.Errorf("%+v missing gv:%d", reflect_type, i) - } - serialized_value.TypeStack = append(serialized_value.TypeStack, field_value.TypeStack...) - if value != nil { - serialized_value.Data = append(serialized_value.Data, field_value.Data...) - } - } - return serialized_value, nil }, func(ctx *Context, value SerializedValue)(reflect.Type, *reflect.Value, SerializedValue, error){ return nil, nil, SerializedValue{}, fmt.Errorf("deserialize struct not implemented") @@ -592,14 +363,14 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { } err = ctx.RegisterKind(reflect.Int, NewSerializedType("int"), - func(ctx *Context, ctx_type uint64, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ + func(ctx *Context, ctx_type SerializedType, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ var data []byte = nil if value != nil { data = make([]byte, 8) binary.BigEndian.PutUint64(data, uint64(value.Int())) } return SerializedValue{ - []uint64{ctx_type}, + []SerializedType{ctx_type}, data, }, nil }, func(ctx *Context, value SerializedValue)(reflect.Type, *reflect.Value, SerializedValue, error){ @@ -618,7 +389,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { } err = ctx.RegisterKind(reflect.Bool, NewSerializedType("bool"), - func(ctx *Context, ctx_type uint64, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ + func(ctx *Context, ctx_type SerializedType, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ var data []byte = nil if value != nil { b := value.Bool() @@ -629,7 +400,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { } } return SerializedValue{ - []uint64{ctx_type}, + []SerializedType{ctx_type}, data, }, nil }, func(ctx *Context, value SerializedValue)(reflect.Type, *reflect.Value, SerializedValue, error){ @@ -657,7 +428,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { } err = ctx.RegisterKind(reflect.Float64, NewSerializedType("float64"), - func(ctx *Context, ctx_type uint64, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ + func(ctx *Context, ctx_type SerializedType, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ var data []byte = nil if value != nil { // TODO: fix if underlying memory layout of float32 changes(or if it's architecture-dependent) @@ -666,7 +437,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { binary.BigEndian.PutUint64(data, val) } return SerializedValue{ - []uint64{ctx_type}, + []SerializedType{ctx_type}, data, }, nil }, func(ctx *Context, value SerializedValue)(reflect.Type, *reflect.Value, SerializedValue, error){ @@ -690,7 +461,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { } err = ctx.RegisterKind(reflect.Float32, NewSerializedType("float32"), - func(ctx *Context, ctx_type uint64, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ + func(ctx *Context, ctx_type SerializedType, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ var data []byte = nil if value != nil { // TODO: fix if underlying memory layout of float32 changes(or if it's architecture-dependent) @@ -699,7 +470,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { binary.BigEndian.PutUint32(data, val) } return SerializedValue{ - []uint64{ctx_type}, + []SerializedType{ctx_type}, data, }, nil }, func(ctx *Context, value SerializedValue)(reflect.Type, *reflect.Value, SerializedValue, error){ @@ -723,13 +494,13 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { } err = ctx.RegisterKind(reflect.Uint32, NewSerializedType("uint32"), - func(ctx *Context, ctx_type uint64, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ + func(ctx *Context, ctx_type SerializedType, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ data := make([]byte, 4) if value != nil { binary.BigEndian.PutUint32(data, uint32(value.Uint())) } return SerializedValue{ - []uint64{ctx_type}, + []SerializedType{ctx_type}, data, }, nil }, func(ctx *Context, value SerializedValue)(reflect.Type, *reflect.Value, SerializedValue, error){ @@ -751,10 +522,10 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { } err = ctx.RegisterKind(reflect.String, NewSerializedType("string"), - func(ctx *Context, ctx_type uint64, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ + func(ctx *Context, ctx_type SerializedType, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ if value == nil { return SerializedValue{ - []uint64{ctx_type}, + []SerializedType{ctx_type}, nil, }, nil } @@ -763,7 +534,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { str := value.String() binary.BigEndian.PutUint64(data, uint64(len(str))) return SerializedValue{ - []uint64{uint64(ctx_type)}, + []SerializedType{SerializedType(ctx_type)}, append(data, []byte(str)...), }, nil }, func(ctx *Context, value SerializedValue)(reflect.Type, *reflect.Value, SerializedValue, error){ @@ -789,7 +560,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { err = ctx.RegisterKind(reflect.Array, NewSerializedType("array"), - func(ctx *Context, ctx_type uint64, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ + func(ctx *Context, ctx_type SerializedType, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ var data []byte if value == nil { data = nil @@ -799,7 +570,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { data := make([]byte, 8) binary.BigEndian.PutUint64(data, uint64(value.Len())) - var type_stack []uint64 = nil + var type_stack []SerializedType = nil for i := 0; i < value.Len(); i += 1 { val := value.Index(i) element, err := serializeValue(ctx, reflect_type.Elem(), &val) @@ -807,7 +578,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { return SerializedValue{}, err } if type_stack == nil { - type_stack = append([]uint64{ctx_type}, element.TypeStack...) + type_stack = append([]SerializedType{ctx_type}, element.TypeStack...) } data = append(data, element.Data...) } @@ -819,7 +590,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { } return SerializedValue{ - append([]uint64{ctx_type}, elem.TypeStack...), + append([]SerializedType{ctx_type}, elem.TypeStack...), data, }, nil }, func(ctx *Context, value SerializedValue)(reflect.Type, *reflect.Value, SerializedValue, error){ @@ -830,9 +601,9 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { } err = ctx.RegisterKind(reflect.Interface, NewSerializedType("interface"), - func(ctx *Context, ctx_type uint64, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ + func(ctx *Context, ctx_type SerializedType, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ var data []byte - type_stack := []uint64{} + type_stack := []SerializedType{} if value == nil { data = nil } else if value.IsZero() { @@ -847,7 +618,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { type_stack = elem.TypeStack } return SerializedValue{ - append([]uint64{ctx_type}, type_stack...), + append([]SerializedType{ctx_type}, type_stack...), data, }, nil }, func(ctx *Context, value SerializedValue)(reflect.Type, *reflect.Value, SerializedValue, error){ @@ -859,170 +630,23 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { err = ctx.RegisterKind(reflect.Map, NewSerializedType("map"), - func(ctx *Context, ctx_type uint64, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ - var data []byte - if value == nil { - data = nil - } else if value.IsZero() { - data = []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} - } else if value.Len() == 0 { - data = []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} - } else { - map_iter := value.MapRange() - key_data := []byte{} - val_data := []byte{} - var key_types []uint64 = nil - var val_types []uint64 = nil - map_len := 0 - for map_iter.Next() { - map_len += 1 - key_value := map_iter.Key() - val_value := map_iter.Value() - - key, err := serializeValue(ctx, reflect_type.Key(), &key_value) - if err != nil { - return SerializedValue{}, err - } - val, err := serializeValue(ctx, reflect_type.Elem(), &val_value) - if err != nil { - return SerializedValue{}, err - } - - if key_types == nil { - key_types = key.TypeStack - val_types = val.TypeStack - } - - key_data = append(key_data, key.Data...) - val_data = append(val_data, val.Data...) - } - - type_stack := []uint64{ctx_type} - type_stack = append(type_stack, key_types...) - type_stack = append(type_stack, val_types...) - - data := make([]byte, 8) - binary.BigEndian.PutUint64(data, uint64(map_len)) - data = append(data, key_data...) - data = append(data, val_data...) - return SerializedValue{ - type_stack, - data, - }, nil - } - key, err := serializeValue(ctx, reflect_type.Key(), nil) - if err != nil { - return SerializedValue{}, err - } - elem, err := serializeValue(ctx, reflect_type.Elem(), nil) - if err != nil { - return SerializedValue{}, err - } - type_stack := []uint64{ctx_type} - type_stack = append(type_stack, key.TypeStack...) - type_stack = append(type_stack, elem.TypeStack...) - return SerializedValue{ - type_stack, - data, - }, nil + func(ctx *Context, ctx_type SerializedType, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ + return SerializedValue{}, fmt.Errorf("serialize map unimplemented") }, func(ctx *Context, value SerializedValue)(reflect.Type, *reflect.Value, SerializedValue, error){ - if value.Data == nil { - var key_type, elem_type reflect.Type - key_type, _, value, err = DeserializeValue(ctx, value, 1) - if err != nil { - return nil, nil, SerializedValue{}, err - } - elem_type, _, value, err = DeserializeValue(ctx, value, 1) - if err != nil { - return nil, nil, SerializedValue{}, err - } - return reflect.MapOf(key_type, elem_type), nil, value, nil - } else if len(value.Data) < 8 { - return nil, nil, SerializedValue{}, fmt.Errorf("Not enough data to deserialize map") - } else { - map_len := binary.BigEndian.Uint64(value.Data[0:8]) - value.Data = value.Data[8:] - if map_len == 0xFFFFFFFFFFFFFFFF { - temp_value := SerializedValue{ - value.TypeStack, - nil, - } - - var key_type, elem_type reflect.Type - key_type, _, temp_value, err = DeserializeValue(ctx, temp_value, 1) - if err != nil { - return nil, nil, SerializedValue{}, err - } - elem_type, _, temp_value, err = DeserializeValue(ctx, temp_value, 1) - if err != nil { - return nil, nil, SerializedValue{}, err - } - - map_type := reflect.MapOf(key_type, elem_type) - map_value := reflect.New(map_type).Elem() - - return map_type, &map_value, SerializedValue{ - temp_value.TypeStack, - value.Data, - }, nil - } else if map_len == 0x00 { - temp_value := SerializedValue{ - value.TypeStack, - nil, - } - - var key_type, elem_type reflect.Type - key_type, _, temp_value, err = DeserializeValue(ctx, temp_value, 1) - if err != nil { - return nil, nil, SerializedValue{}, err - } - elem_type, _, temp_value, err = DeserializeValue(ctx, temp_value, 1) - if err != nil { - return nil, nil, SerializedValue{}, err - } - - map_type := reflect.MapOf(key_type, elem_type) - map_value := reflect.MakeMap(map_type) - - return map_type, &map_value, SerializedValue{ - temp_value.TypeStack, - value.Data, - }, nil - } else { - var key_type, elem_type reflect.Type - var key_values, elem_values []reflect.Value - key_type, key_values, value, err = DeserializeValue(ctx, value, int(map_len)) - if err != nil { - return nil, nil, SerializedValue{}, err - } - elem_type, elem_values, value, err = DeserializeValue(ctx, value, int(map_len)) - if err != nil { - return nil, nil, SerializedValue{}, err - } - - map_type := reflect.MapOf(key_type, elem_type) - map_value := reflect.MakeMap(map_type) - - for i := 0; i < int(map_len); i += 1 { - map_value.SetMapIndex(key_values[i], elem_values[i]) - } - - return map_type, &map_value, value, nil - } - } + return nil, nil, value, fmt.Errorf("deserialize map unimplemented") }) if err != nil { return nil, err } err = ctx.RegisterKind(reflect.Int8, NewSerializedType("int8"), - func(ctx *Context, ctx_type uint64, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ + func(ctx *Context, ctx_type SerializedType, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ var data []byte = nil if value != nil { data = []byte{byte(value.Int())} } return SerializedValue{ - []uint64{ctx_type}, + []SerializedType{ctx_type}, data, }, nil }, func(ctx *Context, value SerializedValue)(reflect.Type, *reflect.Value, SerializedValue, error){ @@ -1043,13 +667,13 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { } err = ctx.RegisterKind(reflect.Uint8, NewSerializedType("uint8"), - func(ctx *Context, ctx_type uint64, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ + func(ctx *Context, ctx_type SerializedType, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ var data []byte = nil if value != nil { data = []byte{uint8(value.Uint())} } return SerializedValue{ - []uint64{ctx_type}, + []SerializedType{ctx_type}, data, }, nil }, func(ctx *Context, value SerializedValue)(reflect.Type, *reflect.Value, SerializedValue, error){ @@ -1070,14 +694,14 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { } err = ctx.RegisterKind(reflect.Uint16, NewSerializedType("uint16"), - func(ctx *Context, ctx_type uint64, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ + func(ctx *Context, ctx_type SerializedType, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ var data []byte = nil if value != nil { data = make([]byte, 2) binary.BigEndian.PutUint16(data, uint16(value.Uint())) } return SerializedValue{ - []uint64{ctx_type}, + []SerializedType{ctx_type}, data, }, nil }, func(ctx *Context, value SerializedValue)(reflect.Type, *reflect.Value, SerializedValue, error){ @@ -1099,14 +723,14 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { } err = ctx.RegisterKind(reflect.Int16, NewSerializedType("int16"), - func(ctx *Context, ctx_type uint64, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ + func(ctx *Context, ctx_type SerializedType, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ var data []byte = nil if value != nil { data = make([]byte, 2) binary.BigEndian.PutUint16(data, uint16(value.Int())) } return SerializedValue{ - []uint64{ctx_type}, + []SerializedType{ctx_type}, data, }, nil }, func(ctx *Context, value SerializedValue)(reflect.Type, *reflect.Value, SerializedValue, error){ @@ -1128,14 +752,14 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { } err = ctx.RegisterKind(reflect.Int32, NewSerializedType("int32"), - func(ctx *Context, ctx_type uint64, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ + func(ctx *Context, ctx_type SerializedType, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ var data []byte = nil if value != nil { data = make([]byte, 4) binary.BigEndian.PutUint32(data, uint32(value.Int())) } return SerializedValue{ - []uint64{ctx_type}, + []SerializedType{ctx_type}, data, }, nil }, func(ctx *Context, value SerializedValue)(reflect.Type, *reflect.Value, SerializedValue, error){ @@ -1157,14 +781,14 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { } err = ctx.RegisterKind(reflect.Uint, NewSerializedType("uint"), - func(ctx *Context, ctx_type uint64, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ + func(ctx *Context, ctx_type SerializedType, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ var data []byte = nil if value != nil { data = make([]byte, 8) binary.BigEndian.PutUint64(data, value.Uint()) } return SerializedValue{ - []uint64{ctx_type}, + []SerializedType{ctx_type}, data, }, nil }, func(ctx *Context, value SerializedValue)(reflect.Type, *reflect.Value, SerializedValue, error){ @@ -1172,7 +796,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { return reflect.TypeOf(uint(0)), nil, value, nil } else { if len(value.Data) < 8 { - return nil, nil, SerializedValue{}, fmt.Errorf("Not enough data to deserialize uint64") + return nil, nil, SerializedValue{}, fmt.Errorf("Not enough data to deserialize SerializedType") } val := uint(binary.BigEndian.Uint64(value.Data[0:8])) value.Data = value.Data[8:] @@ -1185,23 +809,23 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { return nil, err } - err = ctx.RegisterKind(reflect.Uint64, NewSerializedType("uint64"), - func(ctx *Context, ctx_type uint64, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ + err = ctx.RegisterKind(reflect.Uint64, NewSerializedType("SerializedType"), + func(ctx *Context, ctx_type SerializedType, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ var data []byte = nil if value != nil { data = make([]byte, 8) binary.BigEndian.PutUint64(data, value.Uint()) } return SerializedValue{ - []uint64{ctx_type}, + []SerializedType{ctx_type}, data, }, nil }, func(ctx *Context, value SerializedValue)(reflect.Type, *reflect.Value, SerializedValue, error){ if value.Data == nil { - return reflect.TypeOf(uint64(0)), nil, value, nil + return reflect.TypeOf(SerializedType(0)), nil, value, nil } else { if len(value.Data) < 8 { - return nil, nil, SerializedValue{}, fmt.Errorf("Not enough data to deserialize uint64") + return nil, nil, SerializedValue{}, fmt.Errorf("Not enough data to deserialize SerializedType") } val := binary.BigEndian.Uint64(value.Data[0:8]) value.Data = value.Data[8:] @@ -1215,14 +839,14 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { } err = ctx.RegisterKind(reflect.Int64, NewSerializedType("int64"), - func(ctx *Context, ctx_type uint64, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ + func(ctx *Context, ctx_type SerializedType, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ var data []byte = nil if value != nil { data = make([]byte, 8) binary.BigEndian.PutUint64(data, uint64(value.Int())) } return SerializedValue{ - []uint64{ctx_type}, + []SerializedType{ctx_type}, data, }, nil }, func(ctx *Context, value SerializedValue)(reflect.Type, *reflect.Value, SerializedValue, error){ @@ -1230,7 +854,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { return reflect.TypeOf(int64(0)), nil, value, nil } else { if len(value.Data) < 8 { - return nil, nil, SerializedValue{}, fmt.Errorf("Not enough data to deserialize uint64") + return nil, nil, SerializedValue{}, fmt.Errorf("Not enough data to deserialize SerializedType") } val := int64(binary.BigEndian.Uint64(value.Data[0:8])) value.Data = value.Data[8:] @@ -1243,10 +867,10 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { return nil, err } - err = ctx.RegisterKind(reflect.Slice, NewSerializedType("slice"), - func(ctx *Context, ctx_type uint64, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ + err = ctx.RegisterKind(reflect.Slice, SliceType, + func(ctx *Context, ctx_type SerializedType, reflect_type reflect.Type, value *reflect.Value)(SerializedValue, error){ var data []byte - var type_stack []uint64 = nil + type_stack := []SerializedType{ctx_type} if value == nil { data = nil } else if value.IsZero() { @@ -1256,19 +880,18 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { } else { data := make([]byte, 8) binary.BigEndian.PutUint64(data, uint64(value.Len())) + var element SerializedValue + var err error for i := 0; i < value.Len(); i += 1 { val := value.Index(i) - element, err := serializeValue(ctx, reflect_type.Elem(), &val) + element, err = serializeValue(ctx, reflect_type.Elem(), &val) if err != nil { return SerializedValue{}, err } - if type_stack == nil { - type_stack = append([]uint64{ctx_type}, element.TypeStack...) - } data = append(data, element.Data...) } return SerializedValue{ - type_stack, + append(type_stack, element.TypeStack...), data, }, nil } @@ -1277,12 +900,12 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { return SerializedValue{}, err } return SerializedValue{ - append([]uint64{ctx_type}, element.TypeStack...), + append(type_stack, element.TypeStack...), data, }, nil }, func(ctx *Context, value SerializedValue)(reflect.Type, *reflect.Value, SerializedValue, error){ if value.Data == nil { - elem_type, _, _, err := DeserializeValue(ctx, value, 1) + elem_type, _, _, err := DeserializeValue(ctx, value) if err != nil { return nil, nil, SerializedValue{}, err } @@ -1296,7 +919,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { elem_type, _, remaining, err := DeserializeValue(ctx, SerializedValue{ value.TypeStack, nil, - }, 1) + }) if err != nil { return nil, nil, SerializedValue{}, err } @@ -1307,7 +930,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { value.Data, }, nil } else if slice_length == 0x00 { - elem_type, _, remaining, err := DeserializeValue(ctx, value, 1) + elem_type, _, remaining, err := DeserializeValue(ctx, value) if err != nil { return nil, nil, SerializedValue{}, err } @@ -1317,15 +940,28 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { value.Data, }, nil } else { - elem_type, elements, remaining_data, err := DeserializeValue(ctx, value, int(slice_length)) - if err != nil { - return nil, nil, SerializedValue{}, err - } - reflect_value := reflect.MakeSlice(reflect.SliceOf(elem_type), 0, int(slice_length)) + var reflect_value *reflect.Value = nil + var reflect_type reflect.Type = nil + saved_type_stack := value.TypeStack for i := 0; i < int(slice_length); i += 1 { - reflect_value = reflect.Append(reflect_value, elements[i]) + var element_type reflect.Type + var element_value *reflect.Value + element_type, element_value, value, err = DeserializeValue(ctx, value) + if err != nil { + return nil, nil, value, err + } + if reflect_value == nil { + reflect_type = reflect.SliceOf(element_type) + real_value := reflect.MakeSlice(reflect_type, int(slice_length), int(slice_length)) + reflect_value = &real_value + } + if i != (int(slice_length) - 1) { + value.TypeStack = saved_type_stack + } + slice_index_ptr := reflect_value.Index(i) + slice_index_ptr.Set(*element_value) } - return reflect_value.Type(), &reflect_value, remaining_data, nil + return reflect_type, reflect_value, value, nil } } }) @@ -1334,10 +970,10 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { } err = ctx.RegisterType(reflect.TypeOf(StringError("")), ErrorType, - func(ctx *Context, ctx_type uint64, t reflect.Type, value *reflect.Value) (SerializedValue, error) { + func(ctx *Context, ctx_type SerializedType, t reflect.Type, value *reflect.Value) (SerializedValue, error) { if value == nil { return SerializedValue{ - []uint64{ctx_type}, + []SerializedType{ctx_type}, nil, }, nil } @@ -1347,7 +983,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { str := string(err) binary.BigEndian.PutUint64(data, uint64(len(str))) return SerializedValue{ - []uint64{uint64(ctx_type)}, + []SerializedType{SerializedType(ctx_type)}, append(data, []byte(str)...), }, nil }, func(ctx *Context, value SerializedValue)(reflect.Type, *reflect.Value, SerializedValue, error){ @@ -1355,7 +991,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { }) err = ctx.RegisterType(reflect.TypeOf(RandID()), NewSerializedType("NodeID"), - func(ctx *Context, ctx_type uint64, t reflect.Type, value *reflect.Value) (SerializedValue, error) { + func(ctx *Context, ctx_type SerializedType, t reflect.Type, value *reflect.Value) (SerializedValue, error) { var id_ser []byte = nil if value != nil { var err error = nil @@ -1365,7 +1001,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { } } return SerializedValue{ - []uint64{ctx_type}, + []SerializedType{ctx_type}, id_ser, }, nil }, func(ctx *Context, value SerializedValue)(reflect.Type, *reflect.Value, SerializedValue, error){ @@ -1376,14 +1012,14 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { } err = ctx.RegisterType(reflect.TypeOf(Up), NewSerializedType("SignalDirection"), - func(ctx *Context, ctx_type uint64, t reflect.Type, value *reflect.Value) (SerializedValue, error) { + func(ctx *Context, ctx_type SerializedType, t reflect.Type, value *reflect.Value) (SerializedValue, error) { var data []byte = nil if value != nil { val := value.Interface().(SignalDirection) data = []byte{byte(val)} } return SerializedValue{ - []uint64{ctx_type}, + []SerializedType{ctx_type}, data, }, nil }, func(ctx *Context, value SerializedValue)(reflect.Type, *reflect.Value, SerializedValue, error){ @@ -1394,14 +1030,14 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) { } err = ctx.RegisterType(reflect.TypeOf(ReqState(0)), NewSerializedType("ReqState"), - func(ctx *Context, ctx_type uint64, t reflect.Type, value *reflect.Value) (SerializedValue, error) { + func(ctx *Context, ctx_type SerializedType, t reflect.Type, value *reflect.Value) (SerializedValue, error) { var data []byte = nil if value != nil { val := value.Interface().(ReqState) data = []byte{byte(val)} } return SerializedValue{ - []uint64{ctx_type}, + []SerializedType{ctx_type}, data, }, nil }, func(ctx *Context, value SerializedValue)(reflect.Type, *reflect.Value, SerializedValue, error){ diff --git a/gql.go b/gql.go index 598e5fc..cac3147 100644 --- a/gql.go +++ b/gql.go @@ -569,7 +569,7 @@ func (ctx *GQLExtContext) RegisterField(gql_type graphql.Type, gql_name string, return nil, fmt.Errorf("%s is not in the fields of %+v in the result", acl_name, ext_type) } - if val_ser.TypeStack[0] == uint64(ErrorType) { + if val_ser.TypeStack[0] == ErrorType { return nil, fmt.Errorf(string(val_ser.Data)) } diff --git a/gql_test.go b/gql_test.go index cb29881..0bd3072 100644 --- a/gql_test.go +++ b/gql_test.go @@ -31,33 +31,33 @@ func TestGQLServer(t *testing.T) { gql_id := KeyID(pub) group_policy_1 := NewAllNodesPolicy(Tree{ - uint64(ReadSignalType): Tree{ - uint64(GroupExtType): Tree{ + SerializedType(ReadSignalType): Tree{ + SerializedType(GroupExtType): Tree{ Hash(FieldNameBase, "members"): Tree{}, }, }, - uint64(ReadResultSignalType): nil, - uint64(ErrorSignalType): nil, + SerializedType(ReadResultSignalType): nil, + SerializedType(ErrorSignalType): nil, }) group_policy_2 := NewMemberOfPolicy(map[NodeID]Tree{ gql_id: Tree{ - uint64(LinkSignalType): nil, - uint64(LockSignalType): nil, - uint64(StatusSignalType): nil, - uint64(ReadSignalType): nil, + SerializedType(LinkSignalType): nil, + SerializedType(LockSignalType): nil, + SerializedType(StatusSignalType): nil, + SerializedType(ReadSignalType): nil, }, }) user_policy_1 := NewAllNodesPolicy(Tree{ - uint64(ReadResultSignalType): nil, - uint64(ErrorSignalType): nil, + SerializedType(ReadResultSignalType): nil, + SerializedType(ErrorSignalType): nil, }) user_policy_2 := NewMemberOfPolicy(map[NodeID]Tree{ gql_id: Tree{ - uint64(LinkSignalType): nil, - uint64(ReadSignalType): nil, + SerializedType(LinkSignalType): nil, + SerializedType(ReadSignalType): nil, }, }) diff --git a/lockable_test.go b/lockable_test.go index 0eb7eed..172e0f1 100644 --- a/lockable_test.go +++ b/lockable_test.go @@ -73,7 +73,7 @@ func Test10KLink(t *testing.T) { listener_id := KeyID(l_pub) child_policy := NewPerNodePolicy(map[NodeID]Tree{ listener_id: Tree{ - uint64(LockSignalType): nil, + SerializedType(LockSignalType): nil, }, }) NewLockable := func()(*Node) { @@ -95,7 +95,7 @@ func Test10KLink(t *testing.T) { ctx.Log.Logf("test", "CREATED_10K") l_policy := NewAllNodesPolicy(Tree{ - uint64(LockSignalType): nil, + SerializedType(LockSignalType): nil, }) listener := NewListenerExt(100000) node, err := NewNode(ctx, listener_key, TestLockableType, 10000, diff --git a/node.go b/node.go index a04de6e..11db05c 100644 --- a/node.go +++ b/node.go @@ -206,7 +206,7 @@ func NewErrorField(fstring string, args ...interface{}) SerializedValue { panic(err) } return SerializedValue{ - TypeStack: []uint64{uint64(ErrorType)}, + TypeStack: []SerializedType{ErrorType}, Data: str_ser, } } @@ -570,9 +570,9 @@ func NewNode(ctx *Context, key ed25519.PrivateKey, node_type NodeType, buffer_si } default_policy := NewAllNodesPolicy(Tree{ - uint64(ErrorSignalType): nil, - uint64(ReadResultSignalType): nil, - uint64(StatusSignalType): nil, + SerializedType(ErrorSignalType): nil, + SerializedType(ReadResultSignalType): nil, + SerializedType(StatusSignalType): nil, }) all_nodes_policy, exists := policies[AllNodesPolicyType] @@ -665,7 +665,7 @@ func LoadNode(ctx * Context, id NodeID) (*Node, error) { } else if len(remaining) != 0 { return nil, fmt.Errorf("%d bytes left after parsing node from DB", len(remaining)) } - _, node_val, remaining_data, err := DeserializeValue(ctx, value, 1) + _, node_val, remaining_data, err := DeserializeValue(ctx, value) if err != nil { return nil, err } @@ -677,7 +677,7 @@ func LoadNode(ctx * Context, id NodeID) (*Node, error) { return nil, fmt.Errorf("%d bytes left after desrializing *Node", len(remaining_data.Data)) } - node, ok := node_val[0].Interface().(*Node) + node, ok := node_val.Interface().(*Node) if ok == false { return nil, fmt.Errorf("Deserialized %+v when expecting *Node", reflect.TypeOf(node_val).Elem()) } diff --git a/node_test.go b/node_test.go index 20b734c..d23b29d 100644 --- a/node_test.go +++ b/node_test.go @@ -55,7 +55,7 @@ func TestNodeRead(t *testing.T) { n1_policy := NewPerNodePolicy(map[NodeID]Tree{ n2_id: { - uint64(ReadSignalType): nil, + SerializedType(ReadSignalType): nil, }, }) diff --git a/policy.go b/policy.go index bf5642b..fc9b931 100644 --- a/policy.go +++ b/policy.go @@ -64,12 +64,12 @@ func (policy *RequirementOfPolicy) ContinueAllows(ctx *Context, current PendingA return Deny } - _, reqs_if, _, err := DeserializeValue(ctx, reqs_ser, 1) + _, reqs_if, _, err := DeserializeValue(ctx, reqs_ser) if err != nil { return Deny } - requirements, ok := reqs_if[0].Interface().(map[NodeID]ReqState) + requirements, ok := reqs_if.Interface().(map[NodeID]ReqState) if ok == false { return Deny } @@ -113,12 +113,12 @@ func (policy *MemberOfPolicy) ContinueAllows(ctx *Context, current PendingACL, s return Deny } - _, members_if, _, err := DeserializeValue(ctx, members_ser, 1) + _, members_if, _, err := DeserializeValue(ctx, members_ser) if err != nil { return Deny } - members, ok := members_if[0].Interface().(map[NodeID]string) + members, ok := members_if.Interface().(map[NodeID]string) if ok == false { return Deny } @@ -249,7 +249,7 @@ func (policy *AllNodesPolicy) Copy() Policy { } } -type Tree map[uint64]Tree +type Tree map[SerializedType]Tree func (rule Tree) Allows(action Tree) RuleResult { // If the current rule is nil, it's a wildcard and any action being processed is allowed @@ -311,6 +311,6 @@ func (policy *AllNodesPolicy) Type() PolicyType { } var DefaultPolicy = NewAllNodesPolicy(Tree{ - uint64(ErrorSignalType): nil, - uint64(ReadResultSignalType): nil, + SerializedType(ErrorSignalType): nil, + SerializedType(ReadResultSignalType): nil, }) diff --git a/serialize.go b/serialize.go new file mode 100644 index 0000000..7965ada --- /dev/null +++ b/serialize.go @@ -0,0 +1,227 @@ +package graphvent + +import ( + "crypto/sha512" + "encoding/binary" + "fmt" + "reflect" +) + +const ( + TagBase = "GraphventTag" + ExtTypeBase = "ExtType" + NodeTypeBase = "NodeType" + SignalTypeBase = "SignalType" + PolicyTypeBase = "PolicyType" + SerializedTypeBase = "SerializedType" + FieldNameBase = "FieldName" +) + +func Hash(base string, name string) SerializedType { + digest := append([]byte(base), 0x00) + digest = append(digest, []byte(name)...) + hash := sha512.Sum512(digest) + return SerializedType(binary.BigEndian.Uint64(hash[0:8])) +} + +type SerializedType uint64 +type ExtType SerializedType +type NodeType SerializedType +type SignalType SerializedType +type PolicyType SerializedType + +type TypeSerialize func(*Context,SerializedType,reflect.Type,*reflect.Value) (SerializedValue, error) +type TypeDeserialize func(*Context,SerializedValue) (reflect.Type, *reflect.Value, SerializedValue, error) + +func NewExtType(name string) ExtType { + return ExtType(Hash(ExtTypeBase, name)) +} + +func NewNodeType(name string) NodeType { + return NodeType(Hash(NodeTypeBase, name)) +} + +func NewSignalType(name string) SignalType { + return SignalType(Hash(SignalTypeBase, name)) +} + +func NewPolicyType(name string) PolicyType { + return PolicyType(Hash(PolicyTypeBase, name)) +} + +func NewSerializedType(name string) SerializedType { + return Hash(SerializedTypeBase, name) +} + +var ( + ListenerExtType = NewExtType("LISTENER") + LockableExtType = NewExtType("LOCKABLE") + GQLExtType = NewExtType("GQL") + GroupExtType = NewExtType("GROUP") + ECDHExtType = NewExtType("ECDH") + + GQLNodeType = NewNodeType("GQL") + + StopSignalType = NewSignalType("STOP") + CreateSignalType = NewSignalType("CREATE") + StartSignalType = NewSignalType("START") + ErrorSignalType = NewSignalType("ERROR") + StatusSignalType = NewSignalType("STATUS") + LinkSignalType = NewSignalType("LINK") + LockSignalType = NewSignalType("LOCK") + ReadSignalType = NewSignalType("READ") + ReadResultSignalType = NewSignalType("READ_RESULT") + ACLTimeoutSignalType = NewSignalType("ACL_TIMEOUT") + + MemberOfPolicyType = NewPolicyType("USER_OF") + RequirementOfPolicyType = NewPolicyType("REQUIEMENT_OF") + PerNodePolicyType = NewPolicyType("PER_NODE") + AllNodesPolicyType = NewPolicyType("ALL_NODES") + + ErrorType = NewSerializedType("ERROR") + PointerType = NewSerializedType("POINTER") + SliceType = NewSerializedType("SLICE") +) + +type SerializedValue struct { + TypeStack []SerializedType + Data []byte +} + +func (value SerializedValue) PopType() (SerializedType, SerializedValue, error) { + if len(value.TypeStack) == 0 { + return SerializedType(0), value, fmt.Errorf("No elements in TypeStack") + } + ctx_type := value.TypeStack[0] + value.TypeStack = value.TypeStack[1:] + return ctx_type, value, nil +} + +func (value SerializedValue) PopData(n int) ([]byte, SerializedValue, error) { + if len(value.Data) < n { + return nil, value, fmt.Errorf("Not enough data %d/%d", len(value.Data), n) + } + data := value.Data[0:n] + value.Data = value.Data[n:] + + return data, value, nil +} + +func SerializeValue(ctx *Context, value reflect.Value) (SerializedValue, error) { + val, err := serializeValue(ctx, value.Type(), &value) + ctx.Log.Logf("serialize", "SERIALIZED_VALUE(%+v): %+v - %+v", value.Type(), val.TypeStack, val.Data) + return val, err +} + +func serializeValue(ctx *Context, t reflect.Type, value *reflect.Value) (SerializedValue, error) { + ctx_type, type_exists := ctx.TypeReflects[t] + if type_exists == true { + type_info := ctx.Types[ctx_type] + if type_info.Serialize != nil { + return type_info.Serialize(ctx, ctx_type, t, value) + } + } + + kind := t.Kind() + kind_info, handled := ctx.Kinds[kind] + if handled == false { + return SerializedValue{}, fmt.Errorf("Don't know how to serialize kind %+v", kind) + } else if type_exists == false { + ctx_type = kind_info.Type + } + + return kind_info.Serialize(ctx, ctx_type, t, value) + +} + +func SerializeField(ctx *Context, ext Extension, field_name string) (SerializedValue, error) { + if ext == nil { + return SerializedValue{}, fmt.Errorf("Cannot get fields on nil Extension") + } + ext_value := reflect.ValueOf(ext).Elem() + field := ext_value.FieldByName(field_name) + if field.IsValid() == false { + return SerializedValue{}, fmt.Errorf("%s is not a field in %+v", field_name, ext) + } else { + return SerializeValue(ctx, field) + } +} + +func (value SerializedValue) MarshalBinary() ([]byte, error) { + data := make([]byte, value.SerializedSize()) + binary.BigEndian.PutUint64(data[0:8], uint64(len(value.TypeStack))) + binary.BigEndian.PutUint64(data[8:16], uint64(len(value.Data))) + + for i, t := range(value.TypeStack) { + type_start := (i+2)*8 + type_end := (i+3)*8 + binary.BigEndian.PutUint64(data[type_start:type_end], uint64(t)) + } + + return append(data, value.Data...), nil +} + +func (value SerializedValue) SerializedSize() uint64 { + return uint64((len(value.TypeStack) + 2) * 8) +} + +func ParseSerializedValue(data []byte) (SerializedValue, []byte, error) { + if len(data) < 8 { + return SerializedValue{}, nil, fmt.Errorf("SerializedValue required to have at least 8 bytes when serialized") + } + num_types := int(binary.BigEndian.Uint64(data[0:8])) + data_size := int(binary.BigEndian.Uint64(data[8:16])) + type_stack := make([]SerializedType, num_types) + for i := 0; i < num_types; i += 1 { + type_start := (i+2) * 8 + type_end := (i+3) * 8 + type_stack[i] = SerializedType(binary.BigEndian.Uint64(data[type_start:type_end])) + } + + types_end := 8*(num_types + 2) + data_end := types_end + data_size + return SerializedValue{ + type_stack, + data[types_end:data_end], + }, data[data_end:], nil +} + +func DeserializeValue(ctx *Context, value SerializedValue) (reflect.Type, *reflect.Value, SerializedValue, error) { + ctx.Log.Logf("serialize", "DeserializeValue: %+v", value) + + var deserialize TypeDeserialize = nil + var reflect_type reflect.Type = nil + var reflect_value *reflect.Value = nil + + ctx_type, value, err := value.PopType() + if err != nil { + return nil, nil, value, err + } + + type_info, exists := ctx.Types[SerializedType(ctx_type)] + if exists == true { + deserialize = type_info.Deserialize + reflect_type = type_info.Type + } else { + kind, exists := ctx.KindTypes[SerializedType(ctx_type)] + if exists == false { + return nil, nil, value, fmt.Errorf("Cannot deserialize 0x%x: unknown type/kind", ctx_type) + } + kind_info := ctx.Kinds[kind] + deserialize = kind_info.Deserialize + } + + ctx.Log.Logf("serialize", "Deserializing: %d", ctx_type) + + if value.Data == nil { + reflect_type, _, value, err = deserialize(ctx, value) + } else { + reflect_type, reflect_value, value, err = deserialize(ctx, value) + } + if err != nil { + return nil, nil, value, err + } + + ctx.Log.Logf("serialize", "DeserializeValue: DONE %+v - %+v - %+v", value, reflect_type, reflect_value) + return reflect_type, reflect_value, value, nil +} diff --git a/serialize_test.go b/serialize_test.go index d63c5ab..ebc65f0 100644 --- a/serialize_test.go +++ b/serialize_test.go @@ -27,13 +27,6 @@ func TestSerializeBasic(t *testing.T) { testSerializeSliceSlice[[][]int](t, ctx, [][]int{{123, 456, 789, 101112}, {3253, 2341, 735, 212}, {123, 51}, nil}) testSerializeSliceSlice[[][]string](t, ctx, [][]string{{"123", "456", "789", "101112"}, {"3253", "2341", "735", "212"}, {"123", "51"}, nil}) - testSerializeMap(t, ctx, map[int]int{ - 1: 2, - 3: 4, - 5: 6, - 7: 8, - }) - testSerialize(t, ctx, struct{ int `gv:"0"` string `gv:"1"` @@ -105,7 +98,7 @@ func testSerialize[T any](t *testing.T, ctx *Context, val T) T { t.Fatal("Data remaining after deserializing value") } - val_type, deserialized_values, remaining_deserialize, err := DeserializeValue(ctx, val_parsed, 1) + val_type, deserialized_values, remaining_deserialize, err := DeserializeValue(ctx, val_parsed) fatalErr(t, err) if len(remaining_deserialize.Data) != 0 { @@ -116,12 +109,10 @@ func testSerialize[T any](t *testing.T, ctx *Context, val T) T { t.Fatal(fmt.Sprintf("DeserializeValue returned wrong reflect.Type %+v - %+v", val_type, reflect.TypeOf(val))) } else if deserialized_values == nil { t.Fatal("DeserializeValue returned no []reflect.Value") - } else if len(deserialized_values) == 0 { - t.Fatal("DeserializeValue returned empty []reflect.Value") - } else if len(deserialized_values) > 1 { - t.Fatal("DeserializeValue returned wrong length []reflect.Value") - } else if deserialized_values[0].CanConvert(val_type) == false { + } else if deserialized_values == nil { + t.Fatal("DeserializeValue returned nil *reflect.Value") + } else if deserialized_values.CanConvert(val_type) == false { t.Fatal("DeserializeValue returned value that can't convert to original value") } - return deserialized_values[0].Interface().(T) + return deserialized_values.Interface().(T) } diff --git a/signal.go b/signal.go index 2705607..b858d85 100644 --- a/signal.go +++ b/signal.go @@ -144,7 +144,7 @@ func (signal *CreateSignal) Header() *SignalHeader { } func (signal *CreateSignal) Permission() Tree { return Tree{ - uint64(CreateSignalType): nil, + SerializedType(CreateSignalType): nil, } } @@ -162,7 +162,7 @@ func (signal *StartSignal) Header() *SignalHeader { } func (signal *StartSignal) Permission() Tree { return Tree{ - uint64(StartSignalType): nil, + SerializedType(StartSignalType): nil, } } func NewStartSignal() *StartSignal { @@ -179,7 +179,7 @@ func (signal *StopSignal) Header() *SignalHeader { } func (signal *StopSignal) Permission() Tree { return Tree{ - uint64(StopSignalType): nil, + SerializedType(StopSignalType): nil, } } func NewStopSignal() *StopSignal { @@ -250,7 +250,7 @@ func (signal *ErrorSignal) Deserialize(ctx *Context, data []byte) error { } func (signal *ErrorSignal) Permission() Tree { return Tree{ - uint64(ErrorSignalType): nil, + SerializedType(ErrorSignalType): nil, } } func NewErrorSignal(req_id uuid.UUID, fmt_string string, args ...interface{}) Signal { @@ -268,7 +268,7 @@ func (signal *ACLTimeoutSignal) Header() *SignalHeader { } func (signal *ACLTimeoutSignal) Permission() Tree { return Tree{ - uint64(ACLTimeoutSignalType): nil, + SerializedType(ACLTimeoutSignalType): nil, } } func NewACLTimeoutSignal(req_id uuid.UUID) *ACLTimeoutSignal { @@ -288,7 +288,7 @@ func (signal *StatusSignal) Header() *SignalHeader { } func (signal *StatusSignal) Permission() Tree { return Tree{ - uint64(StatusSignalType): nil, + SerializedType(StatusSignalType): nil, } } func NewStatusSignal(source NodeID, status string) *StatusSignal { @@ -315,7 +315,7 @@ const ( func (signal *LinkSignal) Permission() Tree { return Tree{ - uint64(LinkSignalType): Tree{ + SerializedType(LinkSignalType): Tree{ Hash(LinkActionBase, signal.Action): nil, }, } @@ -342,7 +342,7 @@ const ( func (signal *LockSignal) Permission() Tree { return Tree{ - uint64(LockSignalType): Tree{ + SerializedType(LockSignalType): Tree{ Hash(LockStateBase, signal.State): nil, }, } @@ -418,9 +418,9 @@ func (signal *ReadSignal) Permission() Tree { for _, field := range(fields) { field_tree[Hash(FieldNameBase, field)] = nil } - ret[uint64(ext)] = field_tree + ret[SerializedType(ext)] = field_tree } - return Tree{uint64(ReadSignalType): ret} + return Tree{SerializedType(ReadSignalType): ret} } func NewReadSignal(exts map[ExtType][]string) *ReadSignal { return &ReadSignal{ @@ -440,7 +440,7 @@ func (signal *ReadResultSignal) Header() *SignalHeader { } func (signal *ReadResultSignal) Permission() Tree { return Tree{ - uint64(ReadResultSignalType): nil, + SerializedType(ReadResultSignalType): nil, } } func NewReadResultSignal(req_id uuid.UUID, node_id NodeID, node_type NodeType, exts map[ExtType]map[string]SerializedValue) *ReadResultSignal {