1/* 2 * Copyright (C) 2017 Christian Muehlhaeuser 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU Affero General Public License as published 6 * by the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU Affero General Public License for more details. 13 * 14 * You should have received a copy of the GNU Affero General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 * 17 * Authors: 18 * Christian Muehlhaeuser <muesli@gmail.com> 19 */ 20 21// Package bees is Beehive's central module system. 22package bees 23 24import ( 25 "errors" 26 "fmt" 27 "net/url" 28 "reflect" 29 "strconv" 30 "strings" 31 "time" 32) 33 34// Placeholders is an array of Placeholder. 35type Placeholders []Placeholder 36 37// Placeholder used by ins & outs of a bee. 38type Placeholder struct { 39 Name string 40 Type string 41 Value interface{} 42} 43 44// SetValue sets a value in the Placeholder slice. 45func (ph *Placeholders) SetValue(name string, _type string, value interface{}) { 46 if ph.Value(name) == nil { 47 p := Placeholder{ 48 Name: name, 49 Type: _type, 50 Value: value, 51 } 52 *ph = append(*ph, p) 53 } else { 54 for i := 0; i < len(*ph); i++ { 55 if (*ph)[i].Name == name { 56 (*ph)[i].Type = _type 57 (*ph)[i].Value = value 58 } 59 } 60 } 61} 62 63// Value retrieves a value from a Placeholder slice. 64func (ph Placeholders) Value(name string) interface{} { 65 for _, p := range ph { 66 if p.Name == name { 67 return p.Value 68 } 69 } 70 71 return nil 72} 73 74// Bind a value from a Placeholder slice. 75func (ph Placeholders) Bind(name string, dst interface{}) error { 76 v := ph.Value(name) 77 if v == nil { 78 return errors.New("Placeholder with name " + name + " not found") 79 } 80 81 return ConvertValue(v, dst) 82} 83 84// ConvertValue tries to convert v to dst. 85func ConvertValue(v interface{}, dst interface{}) error { 86 switch d := dst.(type) { 87 case *string: 88 switch vt := v.(type) { 89 case string: 90 *d = vt 91 case []string: 92 *d = strings.Join(vt, ",") 93 case bool: 94 *d = strconv.FormatBool(vt) 95 case int64: 96 *d = strconv.FormatInt(vt, 10) 97 case float64: 98 *d = strconv.FormatFloat(vt, 'f', -1, 64) 99 case int: 100 *d = strconv.FormatInt(int64(vt), 10) 101 default: 102 panic(fmt.Sprintf("Unhandled type %+v for string conversion", reflect.TypeOf(vt))) 103 } 104 105 case *[]string: 106 switch vt := v.(type) { 107 case []interface{}: 108 *d = []string{} 109 for _, v := range vt { 110 *d = append(*d, v.(string)) 111 } 112 case []string: 113 *d = vt 114 case string: 115 *d = strings.Split(vt, ",") 116 default: 117 panic(fmt.Sprintf("Unhandled type %+v for []string conversion", reflect.TypeOf(vt))) 118 } 119 120 case *bool: 121 switch vt := v.(type) { 122 case bool: 123 *d = vt 124 case string: 125 vt = strings.ToLower(vt) 126 if vt == "true" || vt == "on" || vt == "yes" || vt == "1" || vt == "t" { 127 *d = true 128 } else { 129 *d = false 130 } 131 case int64: 132 *d = vt > 0 133 case int: 134 *d = vt > 0 135 case uint64: 136 *d = vt > 0 137 case uint: 138 *d = vt > 0 139 case float64: 140 *d = vt > 0 141 default: 142 panic(fmt.Sprintf("Unhandled type %+v for bool conversion", reflect.TypeOf(vt))) 143 } 144 145 case *float64: 146 switch vt := v.(type) { 147 case int64: 148 *d = float64(vt) 149 case int32: 150 *d = float64(vt) 151 case int16: 152 *d = float64(vt) 153 case int8: 154 *d = float64(vt) 155 case int: 156 *d = float64(vt) 157 case uint64: 158 *d = float64(vt) 159 case uint32: 160 *d = float64(vt) 161 case uint16: 162 *d = float64(vt) 163 case uint8: 164 *d = float64(vt) 165 case uint: 166 *d = float64(vt) 167 case float64: 168 *d = vt 169 case float32: 170 *d = float64(vt) 171 case string: 172 x, _ := strconv.ParseFloat(vt, 64) 173 *d = float64(x) 174 default: 175 panic(fmt.Sprintf("Unhandled type %+v for float64 conversion", reflect.TypeOf(vt))) 176 } 177 178 case *int: 179 switch vt := v.(type) { 180 case int64: 181 *d = int(vt) 182 case int32: 183 *d = int(vt) 184 case int16: 185 *d = int(vt) 186 case int8: 187 *d = int(vt) 188 case int: 189 *d = vt 190 case uint64: 191 *d = int(vt) 192 case uint32: 193 *d = int(vt) 194 case uint16: 195 *d = int(vt) 196 case uint8: 197 *d = int(vt) 198 case uint: 199 *d = int(vt) 200 case float64: 201 *d = int(vt) 202 case float32: 203 *d = int(vt) 204 case string: 205 *d, _ = strconv.Atoi(vt) 206 default: 207 panic(fmt.Sprintf("Unhandled type %+v for int conversion", reflect.TypeOf(vt))) 208 } 209 210 case *time.Time: 211 switch vt := v.(type) { 212 case time.Time: 213 *d = vt 214 case int: 215 *d = time.Unix(int64(vt), 0) 216 case int64: 217 *d = time.Unix(vt, 0) 218 default: 219 panic(fmt.Sprintf("Unhandled type %+v for time.Time conversion", reflect.TypeOf(vt))) 220 } 221 222 case *url.Values: 223 switch vt := v.(type) { 224 case string: 225 *d, _ = url.ParseQuery(vt) 226 default: 227 panic(fmt.Sprintf("Unhandled type %+v for url.Values conversion", reflect.TypeOf(vt))) 228 } 229 230 default: 231 panic(fmt.Sprintf("Unhandled dst type %+v", reflect.TypeOf(dst))) 232 } 233 234 return nil 235} 236