mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00
189 lines
5.4 KiB
Go
189 lines
5.4 KiB
Go
package main
|
|
|
|
import (
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"google.golang.org/protobuf/encoding/protojson"
|
|
"google.golang.org/protobuf/proto"
|
|
|
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/server/grpcserver/protowire"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
func parseCommand(args []string, commandDescs []*commandDescription) (*protowire.KaspadMessage, error) {
|
|
commandName, parameterStrings := args[0], args[1:]
|
|
|
|
var commandDesc *commandDescription
|
|
for _, cd := range commandDescs {
|
|
if cd.name == commandName {
|
|
commandDesc = cd
|
|
break
|
|
}
|
|
}
|
|
if commandDesc == nil {
|
|
return nil, errors.Errorf("unknown command: %s. Use --list-commands to list all commands", commandName)
|
|
}
|
|
if len(parameterStrings) != len(commandDesc.parameters) {
|
|
return nil, errors.Errorf("command '%s' expects %d parameters but got %d",
|
|
commandName, len(commandDesc.parameters), len(parameterStrings))
|
|
}
|
|
|
|
commandValue := reflect.New(unwrapCommandType(commandDesc.typeof))
|
|
for i, parameterDesc := range commandDesc.parameters {
|
|
parameterValue, err := stringToValue(parameterDesc, parameterStrings[i])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
setField(commandValue, parameterValue, parameterDesc)
|
|
}
|
|
|
|
return generateKaspadMessage(commandValue, commandDesc)
|
|
}
|
|
|
|
func setField(commandValue reflect.Value, parameterValue reflect.Value, parameterDesc *parameterDescription) {
|
|
parameterField := commandValue.Elem().FieldByName(parameterDesc.name)
|
|
|
|
parameterField.Set(parameterValue)
|
|
}
|
|
|
|
func stringToValue(parameterDesc *parameterDescription, valueStr string) (reflect.Value, error) {
|
|
if valueStr == "-" {
|
|
return reflect.Zero(parameterDesc.typeof), nil
|
|
}
|
|
|
|
var value interface{}
|
|
var err error
|
|
switch parameterDesc.typeof.Kind() {
|
|
case reflect.Bool:
|
|
value, err = strconv.ParseBool(valueStr)
|
|
if err != nil {
|
|
return reflect.Value{}, errors.WithStack(err)
|
|
}
|
|
case reflect.Int8:
|
|
var valueInt64 int64
|
|
valueInt64, err = strconv.ParseInt(valueStr, 10, 8)
|
|
if err != nil {
|
|
return reflect.Value{}, errors.WithStack(err)
|
|
}
|
|
value = int8(valueInt64)
|
|
case reflect.Int16:
|
|
var valueInt64 int64
|
|
valueInt64, err = strconv.ParseInt(valueStr, 10, 16)
|
|
if err != nil {
|
|
return reflect.Value{}, errors.WithStack(err)
|
|
}
|
|
value = int16(valueInt64)
|
|
case reflect.Int32:
|
|
var valueInt64 int64
|
|
valueInt64, err = strconv.ParseInt(valueStr, 10, 32)
|
|
if err != nil {
|
|
return reflect.Value{}, errors.WithStack(err)
|
|
}
|
|
value = int32(valueInt64)
|
|
case reflect.Int64:
|
|
value, err = strconv.ParseInt(valueStr, 10, 64)
|
|
if err != nil {
|
|
return reflect.Value{}, errors.WithStack(err)
|
|
}
|
|
case reflect.Uint8:
|
|
var valueUInt64 uint64
|
|
valueUInt64, err = strconv.ParseUint(valueStr, 10, 8)
|
|
if err != nil {
|
|
return reflect.Value{}, errors.WithStack(err)
|
|
}
|
|
value = uint8(valueUInt64)
|
|
case reflect.Uint16:
|
|
var valueUInt64 uint64
|
|
valueUInt64, err = strconv.ParseUint(valueStr, 10, 16)
|
|
if err != nil {
|
|
return reflect.Value{}, errors.WithStack(err)
|
|
}
|
|
value = uint16(valueUInt64)
|
|
case reflect.Uint32:
|
|
var valueUInt64 uint64
|
|
valueUInt64, err = strconv.ParseUint(valueStr, 10, 32)
|
|
if err != nil {
|
|
return reflect.Value{}, errors.WithStack(err)
|
|
}
|
|
value = uint32(valueUInt64)
|
|
case reflect.Uint64:
|
|
value, err = strconv.ParseUint(valueStr, 10, 64)
|
|
if err != nil {
|
|
return reflect.Value{}, errors.WithStack(err)
|
|
}
|
|
case reflect.Float32:
|
|
var valueFloat64 float64
|
|
valueFloat64, err = strconv.ParseFloat(valueStr, 32)
|
|
if err != nil {
|
|
return reflect.Value{}, errors.WithStack(err)
|
|
}
|
|
value = float32(valueFloat64)
|
|
case reflect.Float64:
|
|
value, err = strconv.ParseFloat(valueStr, 64)
|
|
if err != nil {
|
|
return reflect.Value{}, errors.WithStack(err)
|
|
}
|
|
case reflect.String:
|
|
value = valueStr
|
|
case reflect.Struct:
|
|
pointer := reflect.New(parameterDesc.typeof) // create pointer to this type
|
|
fieldInterface := pointer.Interface().(proto.Message)
|
|
err := protojson.Unmarshal([]byte(valueStr), fieldInterface)
|
|
if err != nil {
|
|
return reflect.Value{}, errors.WithStack(err)
|
|
}
|
|
// Unpointer the value once it's ready
|
|
fieldInterfaceValue := reflect.ValueOf(fieldInterface)
|
|
value = fieldInterfaceValue.Elem().Interface()
|
|
case reflect.Ptr:
|
|
dummyParameterDesc := ¶meterDescription{
|
|
name: "valuePointedTo",
|
|
typeof: parameterDesc.typeof.Elem(),
|
|
}
|
|
valuePointedTo, err := stringToValue(dummyParameterDesc, valueStr)
|
|
if err != nil {
|
|
return reflect.Value{}, errors.WithStack(err)
|
|
}
|
|
pointer := pointerToValue(valuePointedTo)
|
|
|
|
value = pointer.Interface()
|
|
|
|
case reflect.Slice:
|
|
sliceType := parameterDesc.typeof.Elem()
|
|
if sliceType.Kind() != reflect.String {
|
|
return reflect.Value{},
|
|
errors.Errorf("Unsupported slice type '%s' for parameter '%s'",
|
|
sliceType,
|
|
parameterDesc.name)
|
|
}
|
|
if valueStr == "" {
|
|
value = []string{}
|
|
} else {
|
|
value = strings.Split(valueStr, ",")
|
|
}
|
|
// Int and uint are not supported because their size is platform-dependant
|
|
case reflect.Int,
|
|
reflect.Uint,
|
|
// Other types are not supported simply because they are not used in any command right now
|
|
// but support can be added if and when needed
|
|
reflect.Func,
|
|
reflect.Interface,
|
|
reflect.Map,
|
|
reflect.UnsafePointer,
|
|
reflect.Invalid,
|
|
reflect.Uintptr,
|
|
reflect.Complex64,
|
|
reflect.Complex128,
|
|
reflect.Array,
|
|
reflect.Chan:
|
|
fallthrough
|
|
default:
|
|
return reflect.Value{},
|
|
errors.Errorf("Unsupported type '%s' for parameter '%s'", parameterDesc.typeof.Kind(), parameterDesc.name)
|
|
}
|
|
|
|
return reflect.ValueOf(value), nil
|
|
}
|