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 }