func (o *Onion) GetStringDefault(key string, def string) string {
	v, ok := o.Get(key)
	if !ok {
		return def
	}
	s, ok := v.(string)
	if !ok {
		return def
	}
	return s
}
GetStringDefault get a string from Onion. if the value is not exists or if tha value is not
string, return the default
package onion
import (
	"context"
	"reflect"
	"strconv"
	"strings"
	"sync"
	"time"
)
type Layer interface {
	Load() map[string]interface{}
	Watch() <-chan map[string]interface{}
}
var o = &Onion{}
type Onion struct {
	lock sync.RWMutex
	delimiter string
	ll        []Layer
	data map[Layer]map[string]interface{}
	reload chan struct{}
}
func (o *Onion) watchLayer(ctx context.Context, l Layer) {
	c := l.Watch()
	if c == nil {
		return
	}
	for {
		select {
		case data, ok := <-c:
			if !ok {
				return
			}
			o.setLayerData(l, data, true)
		case <-ctx.Done():
			return
		}
	}
}
func (o *Onion) setLayerData(l Layer, data map[string]interface{}, watch bool) {
	o.lock.Lock()
	defer o.lock.Unlock()
	if o.data == nil {
		o.data = make(map[Layer]map[string]interface{})
	}
	o.data[l] = data
	if !watch {
		return
	}
	if o.reload != nil {
		close(o.reload)
		o.reload = nil
	}
}
func AddLayersContext(ctx context.Context, l ...Layer) {
	o.AddLayersContext(ctx, l...)
}
func (o *Onion) AddLayersContext(ctx context.Context, l ...Layer) {
	if len(l) == 0 {
		return
	}
	o.lock.Lock()
	o.ll = append(o.ll, l...)
	o.lock.Unlock()
	for i := range l {
		o.setLayerData(l[i], l[i].Load(), false)
		go o.watchLayer(ctx, l[i])
	}
}
func AddLayers(l ...Layer) {
	o.AddLayersContext(context.Background(), l...)
}
func (o *Onion) AddLayers(l ...Layer) {
	o.AddLayersContext(context.Background(), l...)
}
func GetDelimiter() string {
	return o.GetDelimiter()
}
func (o *Onion) GetDelimiter() string {
	if o.delimiter == "" {
		o.delimiter = "."
	}
	return o.delimiter
}
func SetDelimiter(d string) {
	o.SetDelimiter(d)
}
func (o *Onion) SetDelimiter(d string) {
	o.delimiter = d
}
func ReloadWatch() <-chan struct{} {
	return o.ReloadWatch()
}
func (o *Onion) ReloadWatch() <-chan struct{} {
	o.lock.Lock()
	defer o.lock.Unlock()
	if o.reload == nil {
		o.reload = make(chan struct{})
	}
	return o.reload
}
func Get(key string) (interface{}, bool) {
	return o.Get(key)
}
func (o *Onion) Get(key string) (interface{}, bool) {
	o.lock.RLock()
	defer o.lock.RUnlock()
	path := strings.Split(key, o.GetDelimiter())
	for i := len(o.ll); i > 0; i-- {
		v, ok := searchStringMap(o.data[o.ll[i-1]], path...)
		if ok {
			return v, ok
		}
	}
	return nil, false
}
func GetIntDefault(key string, def int) int {
	return o.GetIntDefault(key, def)
}
func (o *Onion) GetIntDefault(key string, def int) int {
	return int(o.GetInt64Default(key, int64(def)))
}
func GetInt(key string) int {
	return o.GetInt(key)
}
func (o *Onion) GetInt(key string) int {
	return o.GetIntDefault(key, 0)
}
func GetInt64Default(key string, def int64) int64 {
	return o.GetInt64Default(key, def)
}
func (o *Onion) GetInt64Default(key string, def int64) int64 {
	v, ok := o.Get(key)
	if !ok {
		return def
	}
	switch nv := v.(type) {
	case string:
		i, err := strconv.ParseInt(nv, 10, 64)
		if err != nil {
			return def
		}
		return i
	case int:
		return int64(nv)
	case int64:
		return nv
	case float32:
		return int64(nv)
	case float64:
		return int64(nv)
	default:
		return def
	}
}
func GetInt64(key string) int64 {
	return o.GetInt64(key)
}
func (o *Onion) GetInt64(key string) int64 {
	return o.GetInt64Default(key, 0)
}
func GetFloat32Default(key string, def float32) float32 {
	return o.GetFloat32Default(key, def)
}
func (o *Onion) GetFloat32Default(key string, def float32) float32 {
	return float32(o.GetFloat64Default(key, float64(def)))
}
func GetFloat32(key string) float32 {
	return o.GetFloat32(key)
}
func (o *Onion) GetFloat32(key string) float32 {
	return o.GetFloat32Default(key, 0)
}
func GetFloat64Default(key string, def float64) float64 {
	return o.GetFloat64Default(key, def)
}
func (o *Onion) GetFloat64Default(key string, def float64) float64 {
	v, ok := o.Get(key)
	if !ok {
		return def
	}
	switch nv := v.(type) {
	case string:
		f, err := strconv.ParseFloat(nv, 64)
		if err != nil {
			return def
		}
		return f
	case int:
		return float64(nv)
	case int64:
		return float64(nv)
	case float32:
		return float64(nv)
	case float64:
		return nv
	default:
		return def
	}
}
func GetFloat64(key string) float64 {
	return o.GetFloat64(key)
}
func (o *Onion) GetFloat64(key string) float64 {
	return o.GetFloat64Default(key, 0)
}
func GetStringDefault(key string, def string) string {
	return o.GetStringDefault(key, def)
}