github.com/10XDev/rclone@v1.52.3-0.20200626220027-16af9ab76b2a/fs/rc/params.go (about)

     1  // Parameter parsing
     2  
     3  package rc
     4  
     5  import (
     6  	"encoding/json"
     7  	"fmt"
     8  	"math"
     9  	"strconv"
    10  
    11  	"github.com/pkg/errors"
    12  )
    13  
    14  // Params is the input and output type for the Func
    15  type Params map[string]interface{}
    16  
    17  // ErrParamNotFound - this is returned from the Get* functions if the
    18  // parameter isn't found along with a zero value of the requested
    19  // item.
    20  //
    21  // Returning an error of this type from an rc.Func will cause the http
    22  // method to return http.StatusBadRequest
    23  type ErrParamNotFound string
    24  
    25  // Error turns this error into a string
    26  func (e ErrParamNotFound) Error() string {
    27  	return fmt.Sprintf("Didn't find key %q in input", string(e))
    28  }
    29  
    30  // IsErrParamNotFound returns whether err is ErrParamNotFound
    31  func IsErrParamNotFound(err error) bool {
    32  	_, isNotFound := err.(ErrParamNotFound)
    33  	return isNotFound
    34  }
    35  
    36  // NotErrParamNotFound returns true if err != nil and
    37  // !IsErrParamNotFound(err)
    38  //
    39  // This is for checking error returns of the Get* functions to ignore
    40  // error not found returns and take the default value.
    41  func NotErrParamNotFound(err error) bool {
    42  	return err != nil && !IsErrParamNotFound(err)
    43  }
    44  
    45  // ErrParamInvalid - this is returned from the Get* functions if the
    46  // parameter is invalid.
    47  //
    48  //
    49  // Returning an error of this type from an rc.Func will cause the http
    50  // method to return http.StatusBadRequest
    51  type ErrParamInvalid struct {
    52  	error
    53  }
    54  
    55  // IsErrParamInvalid returns whether err is ErrParamInvalid
    56  func IsErrParamInvalid(err error) bool {
    57  	_, isInvalid := err.(ErrParamInvalid)
    58  	return isInvalid
    59  }
    60  
    61  // Reshape reshapes one blob of data into another via json serialization
    62  //
    63  // out should be a pointer type
    64  //
    65  // This isn't a very efficient way of dealing with this!
    66  func Reshape(out interface{}, in interface{}) error {
    67  	b, err := json.Marshal(in)
    68  	if err != nil {
    69  		return errors.Wrapf(err, "Reshape failed to Marshal")
    70  	}
    71  	err = json.Unmarshal(b, out)
    72  	if err != nil {
    73  		return errors.Wrapf(err, "Reshape failed to Unmarshal")
    74  	}
    75  	return nil
    76  }
    77  
    78  // Get gets a parameter from the input
    79  //
    80  // If the parameter isn't found then error will be of type
    81  // ErrParamNotFound and the returned value will be nil.
    82  func (p Params) Get(key string) (interface{}, error) {
    83  	value, ok := p[key]
    84  	if !ok {
    85  		return nil, ErrParamNotFound(key)
    86  	}
    87  	return value, nil
    88  }
    89  
    90  // GetString gets a string parameter from the input
    91  //
    92  // If the parameter isn't found then error will be of type
    93  // ErrParamNotFound and the returned value will be "".
    94  func (p Params) GetString(key string) (string, error) {
    95  	value, err := p.Get(key)
    96  	if err != nil {
    97  		return "", err
    98  	}
    99  	str, ok := value.(string)
   100  	if !ok {
   101  		return "", ErrParamInvalid{errors.Errorf("expecting string value for key %q (was %T)", key, value)}
   102  	}
   103  	return str, nil
   104  }
   105  
   106  // GetInt64 gets an int64 parameter from the input
   107  //
   108  // If the parameter isn't found then error will be of type
   109  // ErrParamNotFound and the returned value will be 0.
   110  func (p Params) GetInt64(key string) (int64, error) {
   111  	value, err := p.Get(key)
   112  	if err != nil {
   113  		return 0, err
   114  	}
   115  	switch x := value.(type) {
   116  	case int:
   117  		return int64(x), nil
   118  	case int64:
   119  		return x, nil
   120  	case float64:
   121  		if x > math.MaxInt64 || x < math.MinInt64 {
   122  			return 0, ErrParamInvalid{errors.Errorf("key %q (%v) overflows int64 ", key, value)}
   123  		}
   124  		return int64(x), nil
   125  	case string:
   126  		i, err := strconv.ParseInt(x, 10, 0)
   127  		if err != nil {
   128  			return 0, ErrParamInvalid{errors.Wrapf(err, "couldn't parse key %q (%v) as int64", key, value)}
   129  		}
   130  		return i, nil
   131  	}
   132  	return 0, ErrParamInvalid{errors.Errorf("expecting int64 value for key %q (was %T)", key, value)}
   133  }
   134  
   135  // GetFloat64 gets a float64 parameter from the input
   136  //
   137  // If the parameter isn't found then error will be of type
   138  // ErrParamNotFound and the returned value will be 0.
   139  func (p Params) GetFloat64(key string) (float64, error) {
   140  	value, err := p.Get(key)
   141  	if err != nil {
   142  		return 0, err
   143  	}
   144  	switch x := value.(type) {
   145  	case float64:
   146  		return x, nil
   147  	case int:
   148  		return float64(x), nil
   149  	case int64:
   150  		return float64(x), nil
   151  	case string:
   152  		f, err := strconv.ParseFloat(x, 64)
   153  		if err != nil {
   154  			return 0, ErrParamInvalid{errors.Wrapf(err, "couldn't parse key %q (%v) as float64", key, value)}
   155  		}
   156  		return f, nil
   157  	}
   158  	return 0, ErrParamInvalid{errors.Errorf("expecting float64 value for key %q (was %T)", key, value)}
   159  }
   160  
   161  // GetBool gets a boolean parameter from the input
   162  //
   163  // If the parameter isn't found then error will be of type
   164  // ErrParamNotFound and the returned value will be false.
   165  func (p Params) GetBool(key string) (bool, error) {
   166  	value, err := p.Get(key)
   167  	if err != nil {
   168  		return false, err
   169  	}
   170  	switch x := value.(type) {
   171  	case int:
   172  		return x != 0, nil
   173  	case int64:
   174  		return x != 0, nil
   175  	case float64:
   176  		return x != 0, nil
   177  	case bool:
   178  		return x, nil
   179  	case string:
   180  		b, err := strconv.ParseBool(x)
   181  		if err != nil {
   182  			return false, ErrParamInvalid{errors.Wrapf(err, "couldn't parse key %q (%v) as bool", key, value)}
   183  		}
   184  		return b, nil
   185  	}
   186  	return false, ErrParamInvalid{errors.Errorf("expecting bool value for key %q (was %T)", key, value)}
   187  }
   188  
   189  // GetStruct gets a struct from key from the input into the struct
   190  // pointed to by out. out must be a pointer type.
   191  //
   192  // If the parameter isn't found then error will be of type
   193  // ErrParamNotFound and out will be unchanged.
   194  func (p Params) GetStruct(key string, out interface{}) error {
   195  	value, err := p.Get(key)
   196  	if err != nil {
   197  		return err
   198  	}
   199  	err = Reshape(out, value)
   200  	if err != nil {
   201  		return ErrParamInvalid{errors.Wrapf(err, "key %q", key)}
   202  	}
   203  	return nil
   204  }
   205  
   206  // GetStructMissingOK works like GetStruct but doesn't return an error
   207  // if the key is missing
   208  func (p Params) GetStructMissingOK(key string, out interface{}) error {
   209  	_, ok := p[key]
   210  	if !ok {
   211  		return nil
   212  	}
   213  	return p.GetStruct(key, out)
   214  }