package runtime import ( "bytes" "encoding/gob" "encoding/json" "fmt" "strings" "sync" ) type Reader interface { Merge(...*KeyValue) error Value(string) (Value, bool) Source() ([]byte, error) Resolve() error } type reader struct { opts options values map[string]any lock sync.Mutex } func newReader(opts options) Reader { return &reader{ opts: opts, values: make(map[string]any), lock: sync.Mutex{}, } } func (r *reader) Merge(kvs ...*KeyValue) error { merged, err := r.cloneMap() if err != nil { return err } for _, kv := range kvs { next := make(map[string]any) if err := r.opts.decoder(kv, next); err != nil { return fmt.Errorf("decode config key %s: %w", kv.Key, err) } if err := r.opts.merge(&merged, convertMap(next)); err != nil { return fmt.Errorf("merge config key %s: %w", kv.Key, err) } } r.lock.Lock() r.values = merged r.lock.Unlock() return nil } func (r *reader) Value(path string) (Value, bool) { r.lock.Lock() defer r.lock.Unlock() if strings.TrimSpace(path) == "" { value := &atomicValue{} value.Store(r.values) return value, true } return readValue(r.values, path) } func (r *reader) Source() ([]byte, error) { r.lock.Lock() defer r.lock.Unlock() return marshalJSON(convertMap(r.values)) } func (r *reader) Resolve() error { r.lock.Lock() defer r.lock.Unlock() return r.opts.resolver(r.values) } func (r *reader) cloneMap() (map[string]any, error) { r.lock.Lock() defer r.lock.Unlock() return cloneMap(r.values) } func cloneMap(src map[string]any) (map[string]any, error) { var buf bytes.Buffer gob.Register(map[string]any{}) gob.Register([]any{}) enc := gob.NewEncoder(&buf) dec := gob.NewDecoder(&buf) if err := enc.Encode(src); err != nil { return nil, err } var clone map[string]any if err := dec.Decode(&clone); err != nil { return nil, err } return clone, nil } func convertMap(src any) any { switch value := src.(type) { case map[string]any: dst := make(map[string]any, len(value)) for k, v := range value { dst[k] = convertMap(v) } return dst case map[any]any: dst := make(map[string]any, len(value)) for k, v := range value { dst[fmt.Sprint(k)] = convertMap(v) } return dst case []any: dst := make([]any, len(value)) for k, v := range value { dst[k] = convertMap(v) } return dst case []byte: return string(value) default: return src } } func readValue(values map[string]any, path string) (Value, bool) { next := values keys := strings.Split(path, ".") last := len(keys) - 1 for idx, key := range keys { value, ok := next[key] if !ok { return nil, false } if idx == last { atomic := &atomicValue{} atomic.Store(value) return atomic, true } child, ok := value.(map[string]any) if !ok { return nil, false } next = child } return nil, false } func marshalJSON(v any) ([]byte, error) { return json.Marshal(v) } func unmarshalJSON(data []byte, v any) error { return json.Unmarshal(data, v) }