github.com/yacovm/fabric@v2.0.0-alpha.0.20191128145320-c5d4087dc723+incompatible/common/channelconfig/standardvalues.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package channelconfig 8 9 import ( 10 "fmt" 11 "reflect" 12 13 "github.com/golang/protobuf/proto" 14 cb "github.com/hyperledger/fabric-protos-go/common" 15 ) 16 17 // DeserializeGroup deserializes the value for all values in a config group 18 func DeserializeProtoValuesFromGroup(group *cb.ConfigGroup, protosStructs ...interface{}) error { 19 sv, err := NewStandardValues(protosStructs...) 20 if err != nil { 21 logger.Panicf("This is a compile time bug only, the proto structures are somehow invalid: %s", err) 22 } 23 24 for key, value := range group.Values { 25 if _, err := sv.Deserialize(key, value.Value); err != nil { 26 return err 27 } 28 } 29 return nil 30 } 31 32 type StandardValues struct { 33 lookup map[string]proto.Message 34 } 35 36 // NewStandardValues accepts a structure which must contain only protobuf message 37 // types. The structure may embed other (non-pointer) structures which satisfy 38 // the same condition. NewStandard values will instantiate memory for all the proto 39 // messages and build a lookup map from structure field name to proto message instance 40 // This is a useful way to easily implement the Values interface 41 func NewStandardValues(protosStructs ...interface{}) (*StandardValues, error) { 42 sv := &StandardValues{ 43 lookup: make(map[string]proto.Message), 44 } 45 46 for _, protosStruct := range protosStructs { 47 logger.Debugf("Initializing protos for %T\n", protosStruct) 48 if err := sv.initializeProtosStruct(reflect.ValueOf(protosStruct)); err != nil { 49 return nil, err 50 } 51 } 52 53 return sv, nil 54 } 55 56 // Deserialize looks up the backing Values proto of the given name, unmarshals the given bytes 57 // to populate the backing message structure, and returns a referenced to the retained deserialized 58 // message (or an error, either because the key did not exist, or there was an an error unmarshaling 59 func (sv *StandardValues) Deserialize(key string, value []byte) (proto.Message, error) { 60 msg, ok := sv.lookup[key] 61 if !ok { 62 return nil, fmt.Errorf("Unexpected key %s", key) 63 } 64 65 err := proto.Unmarshal(value, msg) 66 if err != nil { 67 return nil, err 68 } 69 70 return msg, nil 71 } 72 73 func (sv *StandardValues) initializeProtosStruct(objValue reflect.Value) error { 74 objType := objValue.Type() 75 if objType.Kind() != reflect.Ptr { 76 return fmt.Errorf("Non pointer type") 77 } 78 if objType.Elem().Kind() != reflect.Struct { 79 return fmt.Errorf("Non struct type") 80 } 81 82 numFields := objValue.Elem().NumField() 83 for i := 0; i < numFields; i++ { 84 structField := objType.Elem().Field(i) 85 logger.Debugf("Processing field: %s\n", structField.Name) 86 switch structField.Type.Kind() { 87 case reflect.Ptr: 88 fieldPtr := objValue.Elem().Field(i) 89 if !fieldPtr.CanSet() { 90 return fmt.Errorf("Cannot set structure field %s (unexported?)", structField.Name) 91 } 92 fieldPtr.Set(reflect.New(structField.Type.Elem())) 93 default: 94 return fmt.Errorf("Bad type supplied: %s", structField.Type.Kind()) 95 } 96 97 proto, ok := objValue.Elem().Field(i).Interface().(proto.Message) 98 if !ok { 99 return fmt.Errorf("Field type %T does not implement proto.Message", objValue.Elem().Field(i)) 100 } 101 102 _, ok = sv.lookup[structField.Name] 103 if ok { 104 return fmt.Errorf("Ambiguous field name specified, multiple occurrences of %s", structField.Name) 105 } 106 107 sv.lookup[structField.Name] = proto 108 } 109 110 return nil 111 }