@@ -52,14 +52,15 @@ type Client interface {
5252 Get (key string ) (* consulapi.KVPair , * consulapi.QueryMeta , error )
5353 // WatchGet
5454 WatchGet (key string ) chan * consulapi.KVPair
55- // GetStr get string value
5655 GetStr (key string ) (string , error )
57- // GetInt get string value
5856 GetInt (key string ) (int , error )
57+ GetBool (key string ) (bool , error )
5958 // Put put KVPair
6059 Put (key string , value string ) (* consulapi.WriteMeta , error )
6160 // Load struct
6261 LoadStruct (parent string , i interface {}) error
62+ // Replace struct values
63+ ReplaceFromStruct (parent string , i interface {}) error
6364}
6465
6566type client struct {
@@ -153,6 +154,18 @@ func (c *client) GetInt(key string) (int, error) {
153154 return res , nil
154155}
155156
157+ func (c * client ) GetBool (key string ) (bool , error ) {
158+ v , err := c .GetStr (key )
159+ if err != nil {
160+ return false , err
161+ }
162+ res , err := strconv .ParseBool (string (v ))
163+ if err != nil {
164+ return false , err
165+ }
166+ return res , nil
167+ }
168+
156169// Put KVPair
157170func (c * client ) Put (key string , value string ) (* consulapi.WriteMeta , error ) {
158171 p := & consulapi.KVPair {Key : key , Value : []byte (value )}
@@ -216,11 +229,34 @@ func (c *client) GetServices(service string, tag string) ([]*consulapi.ServiceEn
216229}
217230
218231func (c * client ) LoadStruct (parent string , i interface {}) error {
232+ return c .recursiveLoadStruct (c .getGroupName (parent ), reflect .ValueOf (i ).Elem ())
233+ }
234+
235+ func (c * client ) getGroupName (parent string ) string {
219236 groupName := os .Getenv (groupEnvName )
220237 if groupName != "" {
221238 parent = fmt .Sprintf ("%s/%s" , strings .Trim (groupName , "/" ), parent )
222239 }
223- return c .recursiveLoadStruct (parent , reflect .ValueOf (i ).Elem ())
240+ return parent
241+ }
242+
243+ func (c * client ) getKeyPath (parent string , field reflect.StructField ) (string , error ) {
244+ var tagOptions map [string ]string
245+ var err error
246+ tagOptions , err = c .getTagOptions (field .Tag .Get ("consul" ))
247+ if err != nil {
248+ return "" , err
249+ }
250+
251+ var kvName string
252+ if name , ok := tagOptions ["name" ]; ok {
253+ kvName = name
254+ } else {
255+ kvName = c .normalizeKeyName (field .Name )
256+ }
257+
258+ path := fmt .Sprintf ("%s/%s" , parent , kvName )
259+ return path , nil
224260}
225261
226262func (c * client ) recursiveLoadStruct (parent string , val reflect.Value ) error {
@@ -231,22 +267,12 @@ func (c *client) recursiveLoadStruct(parent string, val reflect.Value) error {
231267 var tagOptions map [string ]string
232268 var err error
233269
234- tag := field .Tag .Get ("consul" )
235- if tag != "" {
236- tagOptions , err = c .getTagOptions (tag )
237- if err != nil {
238- return err
239- }
240- }
241-
242- var kvName string
243- if name , ok := tagOptions ["name" ]; ok {
244- kvName = name
245- } else {
246- kvName = c .normalizeKeyName (field .Name )
270+ tagOptions , err = c .getTagOptions (field .Tag .Get ("consul" ))
271+ if err != nil {
272+ return err
247273 }
248274
249- path := fmt . Sprintf ( "%s/%s" , parent , kvName )
275+ path , err := c . getKeyPath ( parent , field )
250276
251277 if _ , ok := value .Interface ().(time.Time ); ok {
252278 } else if field .Type .Kind () == reflect .Struct {
@@ -278,7 +304,7 @@ func (c *client) recursiveLoadStruct(parent string, val reflect.Value) error {
278304 fieldValue = kv .Value
279305 }
280306
281- v , err := c .normalizeValue (field .Type , fieldValue )
307+ v , err := c .typifyValue (field .Type , fieldValue )
282308 if err != nil {
283309 return err
284310 }
@@ -288,7 +314,7 @@ func (c *client) recursiveLoadStruct(parent string, val reflect.Value) error {
288314 return nil
289315}
290316
291- func (c * client ) normalizeValue (reflectType reflect.Type , value []byte ) (interface {}, error ) {
317+ func (c * client ) typifyValue (reflectType reflect.Type , value []byte ) (interface {}, error ) {
292318 switch reflectType .Kind () {
293319 case reflect .String :
294320 return string (value ), nil
@@ -328,6 +354,57 @@ func (c *client) normalizeValue(reflectType reflect.Type, value []byte) (interfa
328354 return nil , errors .New (fmt .Sprintf ("unsupported type \" %s\" " , reflectType .Kind ().String ()))
329355}
330356
357+ func (c * client ) ReplaceFromStruct (parent string , i interface {}) error {
358+ return c .recursiveReplaceStruct (c .getGroupName (parent ), reflect .ValueOf (i ).Elem ())
359+ }
360+
361+ func (c * client ) recursiveReplaceStruct (parent string , val reflect.Value ) error {
362+ for i := 0 ; i < val .NumField (); i ++ {
363+ value := val .Field (i )
364+ field := val .Type ().Field (i )
365+ var err error
366+
367+ path , err := c .getKeyPath (parent , field )
368+
369+ if _ , ok := value .Interface ().(time.Time ); ok {
370+ } else if field .Type .Kind () == reflect .Struct {
371+ err = c .recursiveReplaceStruct (path , value )
372+ if err != nil {
373+ return err
374+ }
375+ } else {
376+ fieldValue , err := c .stringifyValue (value )
377+ if err != nil {
378+ return err
379+ }
380+ _ , err = c .Put (path , fieldValue )
381+ if err != nil {
382+ return err
383+ }
384+ }
385+ }
386+ return nil
387+ }
388+
389+ func (c * client ) stringifyValue (value reflect.Value ) (string , error ) {
390+ switch value .Type ().Kind () {
391+ case reflect .String :
392+ return value .String (), nil
393+ case reflect .Float32 , reflect .Float64 :
394+ return strconv .FormatFloat (value .Float (), 'f' , - 1 , 64 ), nil
395+ case reflect .Int :
396+ return strconv .FormatInt (value .Int (), 10 ), nil
397+ case reflect .Bool :
398+ return strconv .FormatBool (value .Bool ()), nil
399+ }
400+
401+ if _ , ok := value .Interface ().(time.Duration ); ok {
402+ return strconv .FormatInt (value .Int (), 10 ), nil
403+ }
404+
405+ return "" , errors .New (fmt .Sprintf ("unsupported type \" %s\" " , value .Type ().Kind ().String ()))
406+ }
407+
331408func (c * client ) normalizeKeyName (name string ) string {
332409 s := regexp .MustCompile ("([A-Z]+[^A-Z]*)" ).FindAllString (name , - 1 )
333410 ss := strings .Join (s [:], "." )
@@ -337,6 +414,10 @@ func (c *client) normalizeKeyName(name string) string {
337414func (c * client ) getTagOptions (v string ) (map [string ]string , error ) {
338415 res := make (map [string ]string )
339416
417+ if v == "" {
418+ return res , nil
419+ }
420+
340421 options := strings .Split (v , ";" )
341422 for _ , option := range options {
342423 parts := tagOptionRegexp .FindAllStringSubmatch (option , 1 )
0 commit comments