github.com/stafiprotocol/go-substrate-rpc-client@v1.4.7/pkg/stafidecoder/base.go (about) 1 package stafi_decoder 2 3 import ( 4 "fmt" 5 "reflect" 6 "regexp" 7 "strings" 8 9 "github.com/itering/scale.go/utiles" 10 ) 11 12 var RuntimeCodecType []string 13 14 type ScaleDecoderOption struct { 15 Spec int 16 SubType string 17 ValueList []string 18 Metadata *MetadataStruct 19 FixedLength int 20 } 21 22 type TypeMapping struct { 23 Names []string 24 Types []string 25 } 26 27 type IScaleDecoder interface { 28 Init(data ScaleBytes, option *ScaleDecoderOption) 29 Process() 30 buildStruct() 31 NextBytes(int) []byte 32 GetNextU8() int 33 reset() 34 } 35 36 type ScaleDecoder struct { 37 Data ScaleBytes `json:"-"` 38 TypeString string `json:"-"` 39 SubType string `json:"-"` 40 Value interface{} `json:"-"` 41 RawValue string `json:"-"` 42 TypeMapping *TypeMapping `json:"-"` 43 Metadata *MetadataStruct `json:"-"` 44 Spec int `json:"-"` 45 } 46 47 func (s *ScaleDecoder) Init(data ScaleBytes, option *ScaleDecoderOption) { 48 if option != nil { 49 if option.Metadata != nil { 50 s.Metadata = option.Metadata 51 } 52 if option.SubType != "" { 53 s.SubType = option.SubType 54 } 55 if option.Spec != 0 { 56 s.Spec = option.Spec 57 } 58 } 59 s.Data = data 60 s.RawValue = "" 61 s.Value = nil 62 if s.TypeMapping == nil && s.TypeString != "" { 63 s.buildStruct() 64 } 65 } 66 67 func (s *ScaleDecoder) Process() {} 68 69 func (s *ScaleDecoder) NextBytes(length int) []byte { 70 data := s.Data.GetNextBytes(length) 71 s.RawValue += utiles.BytesToHex(data) 72 return data 73 } 74 75 func (s *ScaleDecoder) GetNextU8() int { 76 b := s.NextBytes(1) 77 if len(b) > 0 { 78 return int(b[0]) 79 } 80 return 0 81 } 82 83 func (s *ScaleDecoder) getNextBool() bool { 84 data := s.NextBytes(1) 85 return utiles.BytesToHex(data) == "01" 86 } 87 88 func (s *ScaleDecoder) reset() { 89 s.Data.Data = []byte{} 90 s.Data.Offset = 0 91 } 92 93 func (s *ScaleDecoder) buildStruct() { 94 if s.TypeString != "" && string(s.TypeString[0]) == "(" && s.TypeString[len(s.TypeString)-1:] == ")" { 95 96 var names, types []string 97 reg := regexp.MustCompile(`\((.*?)\)`) 98 typeString := s.TypeString[1 : len(s.TypeString)-1] 99 typeParts := reg.FindAllString(typeString, -1) 100 for _, part := range typeParts { 101 typeString = strings.ReplaceAll(typeString, part, strings.ReplaceAll(part, ",", "#")) 102 } 103 104 for k, v := range strings.Split(typeString, ",") { 105 types = append(types, strings.ReplaceAll(strings.TrimSpace(v), "#", ",")) 106 names = append(names, fmt.Sprintf("col%d", k+1)) 107 } 108 109 s.TypeMapping = &TypeMapping{Names: names, Types: types} 110 } 111 } 112 113 func (s *ScaleDecoder) ProcessAndUpdateData(typeString string) interface{} { 114 r := RuntimeType{} 115 116 if TypeRegistry == nil { 117 r.Reg() 118 } 119 120 class, value, subType := r.DecoderClass(typeString, s.Spec) 121 if class == nil { 122 panic(fmt.Sprintf("Not found decoder class %s", typeString)) 123 } 124 125 offsetStart := s.Data.Offset 126 127 // init 128 method, exist := class.MethodByName("Init") 129 if !exist { 130 panic(fmt.Sprintf("%s not implement init function", typeString)) 131 } 132 option := ScaleDecoderOption{SubType: subType, Spec: s.Spec, Metadata: s.Metadata} 133 method.Func.Call([]reflect.Value{value, reflect.ValueOf(s.Data), reflect.ValueOf(&option)}) 134 135 // process 136 value.MethodByName("Process").Call(nil) 137 138 s.Data.Offset = int(value.Elem().FieldByName("Data").FieldByName("Offset").Int()) 139 s.Data.Data = value.Elem().FieldByName("Data").FieldByName("Data").Bytes() 140 s.RawValue = utiles.BytesToHex(s.Data.Data[offsetStart:s.Data.Offset]) 141 142 return value.Elem().FieldByName("Value").Interface() 143 }