mirror of
https://github.com/rclone/rclone.git
synced 2024-12-27 17:38:58 +01:00
205 lines
5.4 KiB
Go
205 lines
5.4 KiB
Go
|
// Parameter parsing
|
||
|
|
||
|
package rc
|
||
|
|
||
|
import (
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"math"
|
||
|
"strconv"
|
||
|
|
||
|
"github.com/pkg/errors"
|
||
|
)
|
||
|
|
||
|
// Params is the input and output type for the Func
|
||
|
type Params map[string]interface{}
|
||
|
|
||
|
// ErrParamNotFound - this is returned from the Get* functions if the
|
||
|
// parameter isn't found along with a zero value of the requested
|
||
|
// item.
|
||
|
//
|
||
|
// Returning an error of this type from an rc.Func will cause the http
|
||
|
// method to return http.StatusBadRequest
|
||
|
type ErrParamNotFound string
|
||
|
|
||
|
// Error turns this error into a string
|
||
|
func (e ErrParamNotFound) Error() string {
|
||
|
return fmt.Sprintf("Didn't find key %q in input", string(e))
|
||
|
}
|
||
|
|
||
|
// IsErrParamNotFound returns whether err is ErrParamNotFound
|
||
|
func IsErrParamNotFound(err error) bool {
|
||
|
_, isNotFound := err.(ErrParamNotFound)
|
||
|
return isNotFound
|
||
|
}
|
||
|
|
||
|
// NotErrParamNotFound returns true if err != nil and
|
||
|
// !IsErrParamNotFound(err)
|
||
|
//
|
||
|
// This is for checking error returns of the Get* functions to ignore
|
||
|
// error not found returns and take the default value.
|
||
|
func NotErrParamNotFound(err error) bool {
|
||
|
return err != nil && !IsErrParamNotFound(err)
|
||
|
}
|
||
|
|
||
|
// ErrParamInvalid - this is returned from the Get* functions if the
|
||
|
// parameter is invalid.
|
||
|
//
|
||
|
//
|
||
|
// Returning an error of this type from an rc.Func will cause the http
|
||
|
// method to return http.StatusBadRequest
|
||
|
type ErrParamInvalid struct {
|
||
|
error
|
||
|
}
|
||
|
|
||
|
// IsErrParamInvalid returns whether err is ErrParamInvalid
|
||
|
func IsErrParamInvalid(err error) bool {
|
||
|
_, isInvalid := err.(ErrParamInvalid)
|
||
|
return isInvalid
|
||
|
}
|
||
|
|
||
|
// Reshape reshapes one blob of data into another via json serialization
|
||
|
//
|
||
|
// out should be a pointer type
|
||
|
//
|
||
|
// This isn't a very efficient way of dealing with this!
|
||
|
func Reshape(out interface{}, in interface{}) error {
|
||
|
b, err := json.Marshal(in)
|
||
|
if err != nil {
|
||
|
return errors.Wrapf(err, "Reshape failed to Marshal")
|
||
|
}
|
||
|
err = json.Unmarshal(b, out)
|
||
|
if err != nil {
|
||
|
return errors.Wrapf(err, "Reshape failed to Unmarshal")
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Get gets a parameter from the input
|
||
|
//
|
||
|
// If the parameter isn't found then error will be of type
|
||
|
// ErrParamNotFound and the returned value will be nil.
|
||
|
func (p Params) Get(key string) (interface{}, error) {
|
||
|
value, ok := p[key]
|
||
|
if !ok {
|
||
|
return nil, ErrParamNotFound(key)
|
||
|
}
|
||
|
return value, nil
|
||
|
}
|
||
|
|
||
|
// GetString gets a string parameter from the input
|
||
|
//
|
||
|
// If the parameter isn't found then error will be of type
|
||
|
// ErrParamNotFound and the returned value will be "".
|
||
|
func (p Params) GetString(key string) (string, error) {
|
||
|
value, err := p.Get(key)
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
str, ok := value.(string)
|
||
|
if !ok {
|
||
|
return "", ErrParamInvalid{errors.Errorf("expecting string value for key %q (was %T)", key, value)}
|
||
|
}
|
||
|
return str, nil
|
||
|
}
|
||
|
|
||
|
// GetInt64 gets a int64 parameter from the input
|
||
|
//
|
||
|
// If the parameter isn't found then error will be of type
|
||
|
// ErrParamNotFound and the returned value will be 0.
|
||
|
func (p Params) GetInt64(key string) (int64, error) {
|
||
|
value, err := p.Get(key)
|
||
|
if err != nil {
|
||
|
return 0, err
|
||
|
}
|
||
|
switch x := value.(type) {
|
||
|
case int:
|
||
|
return int64(x), nil
|
||
|
case int64:
|
||
|
return x, nil
|
||
|
case float64:
|
||
|
if x > math.MaxInt64 || x < math.MinInt64 {
|
||
|
return 0, ErrParamInvalid{errors.Errorf("key %q (%v) overflows int64 ", key, value)}
|
||
|
}
|
||
|
return int64(x), nil
|
||
|
case string:
|
||
|
i, err := strconv.ParseInt(x, 10, 0)
|
||
|
if err != nil {
|
||
|
return 0, ErrParamInvalid{errors.Wrapf(err, "couldn't parse key %q (%v) as int64", key, value)}
|
||
|
}
|
||
|
return i, nil
|
||
|
}
|
||
|
return 0, ErrParamInvalid{errors.Errorf("expecting int64 value for key %q (was %T)", key, value)}
|
||
|
}
|
||
|
|
||
|
// GetFloat64 gets a float64 parameter from the input
|
||
|
//
|
||
|
// If the parameter isn't found then error will be of type
|
||
|
// ErrParamNotFound and the returned value will be 0.
|
||
|
func (p Params) GetFloat64(key string) (float64, error) {
|
||
|
value, err := p.Get(key)
|
||
|
if err != nil {
|
||
|
return 0, err
|
||
|
}
|
||
|
switch x := value.(type) {
|
||
|
case float64:
|
||
|
return x, nil
|
||
|
case int:
|
||
|
return float64(x), nil
|
||
|
case int64:
|
||
|
return float64(x), nil
|
||
|
case string:
|
||
|
f, err := strconv.ParseFloat(x, 64)
|
||
|
if err != nil {
|
||
|
return 0, ErrParamInvalid{errors.Wrapf(err, "couldn't parse key %q (%v) as float64", key, value)}
|
||
|
}
|
||
|
return f, nil
|
||
|
}
|
||
|
return 0, ErrParamInvalid{errors.Errorf("expecting float64 value for key %q (was %T)", key, value)}
|
||
|
}
|
||
|
|
||
|
// GetBool gets a boolean parameter from the input
|
||
|
//
|
||
|
// If the parameter isn't found then error will be of type
|
||
|
// ErrParamNotFound and the returned value will be false.
|
||
|
func (p Params) GetBool(key string) (bool, error) {
|
||
|
value, err := p.Get(key)
|
||
|
if err != nil {
|
||
|
return false, err
|
||
|
}
|
||
|
switch x := value.(type) {
|
||
|
case int:
|
||
|
return x != 0, nil
|
||
|
case int64:
|
||
|
return x != 0, nil
|
||
|
case float64:
|
||
|
return x != 0, nil
|
||
|
case bool:
|
||
|
return x, nil
|
||
|
case string:
|
||
|
b, err := strconv.ParseBool(x)
|
||
|
if err != nil {
|
||
|
return false, ErrParamInvalid{errors.Wrapf(err, "couldn't parse key %q (%v) as bool", key, value)}
|
||
|
}
|
||
|
return b, nil
|
||
|
}
|
||
|
return false, ErrParamInvalid{errors.Errorf("expecting bool value for key %q (was %T)", key, value)}
|
||
|
}
|
||
|
|
||
|
// GetStruct gets a struct from key from the input into the struct
|
||
|
// pointed to by out. out must be a pointer type.
|
||
|
//
|
||
|
// If the parameter isn't found then error will be of type
|
||
|
// ErrParamNotFound and out will be unchanged.
|
||
|
func (p Params) GetStruct(key string, out interface{}) error {
|
||
|
value, err := p.Get(key)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
err = Reshape(out, value)
|
||
|
if err != nil {
|
||
|
return ErrParamInvalid{errors.Wrapf(err, "key %q", key)}
|
||
|
}
|
||
|
return nil
|
||
|
}
|