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  }