mirror of
https://github.com/taigrr/jety.git
synced 2026-04-02 03:19:03 -07:00
329 lines
5.7 KiB
Go
329 lines
5.7 KiB
Go
package jety
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// resolve looks up a key in combinedConfig, falling back to envConfig.
|
|
// It supports dot notation (e.g., "services.mas.server") to traverse nested maps.
|
|
func (c *ConfigManager) resolve(key string) (ConfigMap, bool) {
|
|
lower := strings.ToLower(key)
|
|
|
|
// First, try direct lookup (for top-level keys or keys without dots)
|
|
if v, ok := c.combinedConfig[lower]; ok {
|
|
return v, true
|
|
}
|
|
if v, ok := c.envConfig[lower]; ok {
|
|
return v, true
|
|
}
|
|
|
|
// If key contains dots, try traversing nested maps
|
|
if strings.Contains(lower, ".") {
|
|
if v, ok := c.resolveNested(lower, c.combinedConfig); ok {
|
|
return v, true
|
|
}
|
|
if v, ok := c.resolveNested(lower, c.envConfig); ok {
|
|
return v, true
|
|
}
|
|
}
|
|
|
|
return ConfigMap{}, false
|
|
}
|
|
|
|
// resolveNested traverses nested maps using dot-separated key paths.
|
|
func (c *ConfigManager) resolveNested(key string, config map[string]ConfigMap) (ConfigMap, bool) {
|
|
parts := strings.Split(key, ".")
|
|
if len(parts) < 2 {
|
|
return ConfigMap{}, false
|
|
}
|
|
|
|
// Look up the first part in the config
|
|
firstPart := parts[0]
|
|
entry, ok := config[firstPart]
|
|
if !ok {
|
|
return ConfigMap{}, false
|
|
}
|
|
|
|
// Traverse the remaining parts through nested maps
|
|
current := entry.Value
|
|
for i := 1; i < len(parts); i++ {
|
|
m, ok := current.(map[string]any)
|
|
if !ok {
|
|
return ConfigMap{}, false
|
|
}
|
|
|
|
// Try case-insensitive lookup in the nested map
|
|
part := parts[i]
|
|
found := false
|
|
for k, v := range m {
|
|
if strings.EqualFold(k, part) {
|
|
current = v
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
return ConfigMap{}, false
|
|
}
|
|
}
|
|
|
|
return ConfigMap{Key: key, Value: current}, true
|
|
}
|
|
|
|
func (c *ConfigManager) Get(key string) any {
|
|
c.mutex.RLock()
|
|
defer c.mutex.RUnlock()
|
|
v, ok := c.resolve(key)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return v.Value
|
|
}
|
|
|
|
func (c *ConfigManager) GetBool(key string) bool {
|
|
c.mutex.RLock()
|
|
defer c.mutex.RUnlock()
|
|
v, ok := c.resolve(key)
|
|
if !ok {
|
|
return false
|
|
}
|
|
val := v.Value
|
|
switch val := val.(type) {
|
|
case bool:
|
|
return val
|
|
case string:
|
|
return strings.EqualFold(val, "true")
|
|
case int:
|
|
return val != 0
|
|
case float32:
|
|
return val != 0
|
|
case float64:
|
|
return val != 0
|
|
case time.Duration:
|
|
return val > 0
|
|
case nil:
|
|
return false
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func (c *ConfigManager) GetDuration(key string) time.Duration {
|
|
c.mutex.RLock()
|
|
defer c.mutex.RUnlock()
|
|
v, ok := c.resolve(key)
|
|
if !ok {
|
|
return 0
|
|
}
|
|
val := v.Value
|
|
switch val := val.(type) {
|
|
case time.Duration:
|
|
return val
|
|
case string:
|
|
d, err := time.ParseDuration(val)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
return d
|
|
case int:
|
|
return time.Duration(val)
|
|
case int64:
|
|
return time.Duration(val)
|
|
case float32:
|
|
return time.Duration(val)
|
|
case float64:
|
|
return time.Duration(val)
|
|
case nil:
|
|
return 0
|
|
default:
|
|
return 0
|
|
}
|
|
}
|
|
|
|
func (c *ConfigManager) GetString(key string) string {
|
|
c.mutex.RLock()
|
|
defer c.mutex.RUnlock()
|
|
v, ok := c.resolve(key)
|
|
if !ok {
|
|
return ""
|
|
}
|
|
|
|
switch val := v.Value.(type) {
|
|
case string:
|
|
return val
|
|
default:
|
|
return fmt.Sprintf("%v", v.Value)
|
|
}
|
|
}
|
|
|
|
func (c *ConfigManager) GetStringMap(key string) map[string]any {
|
|
c.mutex.RLock()
|
|
defer c.mutex.RUnlock()
|
|
v, ok := c.resolve(key)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
switch val := v.Value.(type) {
|
|
case map[string]any:
|
|
return val
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func (c *ConfigManager) GetStringSlice(key string) []string {
|
|
c.mutex.RLock()
|
|
defer c.mutex.RUnlock()
|
|
v, ok := c.resolve(key)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
switch val := v.Value.(type) {
|
|
case []string:
|
|
return val
|
|
case []any:
|
|
var ret []string
|
|
for _, v := range val {
|
|
switch v := v.(type) {
|
|
case string:
|
|
ret = append(ret, v)
|
|
default:
|
|
ret = append(ret, fmt.Sprintf("%v", v))
|
|
}
|
|
}
|
|
return ret
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func (c *ConfigManager) GetFloat64(key string) float64 {
|
|
c.mutex.RLock()
|
|
defer c.mutex.RUnlock()
|
|
v, ok := c.resolve(key)
|
|
if !ok {
|
|
return 0
|
|
}
|
|
switch val := v.Value.(type) {
|
|
case float64:
|
|
return val
|
|
case float32:
|
|
return float64(val)
|
|
case int:
|
|
return float64(val)
|
|
case int64:
|
|
return float64(val)
|
|
case string:
|
|
f, err := strconv.ParseFloat(val, 64)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
return f
|
|
case nil:
|
|
return 0
|
|
default:
|
|
return 0
|
|
}
|
|
}
|
|
|
|
func (c *ConfigManager) GetInt64(key string) int64 {
|
|
c.mutex.RLock()
|
|
defer c.mutex.RUnlock()
|
|
v, ok := c.resolve(key)
|
|
if !ok {
|
|
return 0
|
|
}
|
|
switch val := v.Value.(type) {
|
|
case int64:
|
|
return val
|
|
case int:
|
|
return int64(val)
|
|
case string:
|
|
i, err := strconv.ParseInt(val, 10, 64)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
return i
|
|
case float32:
|
|
return int64(val)
|
|
case float64:
|
|
return int64(val)
|
|
case nil:
|
|
return 0
|
|
default:
|
|
return 0
|
|
}
|
|
}
|
|
|
|
func (c *ConfigManager) GetInt(key string) int {
|
|
c.mutex.RLock()
|
|
defer c.mutex.RUnlock()
|
|
v, ok := c.resolve(key)
|
|
if !ok {
|
|
return 0
|
|
}
|
|
switch val := v.Value.(type) {
|
|
case int:
|
|
return val
|
|
case int64:
|
|
return int(val)
|
|
case string:
|
|
i, err := strconv.Atoi(val)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
return i
|
|
case float32:
|
|
return int(val)
|
|
case float64:
|
|
return int(val)
|
|
case nil:
|
|
return 0
|
|
default:
|
|
return 0
|
|
}
|
|
}
|
|
|
|
func (c *ConfigManager) GetIntSlice(key string) []int {
|
|
c.mutex.RLock()
|
|
defer c.mutex.RUnlock()
|
|
v, ok := c.resolve(key)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
switch val := v.Value.(type) {
|
|
case []int:
|
|
return val
|
|
case []any:
|
|
var ret []int
|
|
for _, v := range val {
|
|
switch v := v.(type) {
|
|
case int:
|
|
ret = append(ret, v)
|
|
case int64:
|
|
ret = append(ret, int(v))
|
|
case string:
|
|
i, err := strconv.Atoi(v)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
ret = append(ret, i)
|
|
case float32:
|
|
ret = append(ret, int(v))
|
|
case float64:
|
|
ret = append(ret, int(v))
|
|
case nil:
|
|
continue
|
|
default:
|
|
continue
|
|
}
|
|
}
|
|
return ret
|
|
default:
|
|
return nil
|
|
}
|
|
}
|