优化结构
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
// Package runtimeconfig keeps the active database-backed integration settings
|
||||
// and notifies long-lived provider clients when they change.
|
||||
package runtimeconfig
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Kind string
|
||||
Provider string
|
||||
Enabled bool
|
||||
Values json.RawMessage
|
||||
}
|
||||
|
||||
type listener struct {
|
||||
kind string
|
||||
provider string
|
||||
callback func(Config)
|
||||
}
|
||||
|
||||
type Store struct {
|
||||
mu sync.RWMutex
|
||||
values map[string]Config
|
||||
listeners map[uint64]listener
|
||||
nextID uint64
|
||||
}
|
||||
|
||||
func NewStore() *Store {
|
||||
return &Store{values: make(map[string]Config), listeners: make(map[uint64]listener)}
|
||||
}
|
||||
|
||||
func configKey(kind, provider string) string {
|
||||
return strings.ToLower(strings.TrimSpace(kind)) + "/" + strings.ToLower(strings.TrimSpace(provider))
|
||||
}
|
||||
|
||||
func cloneConfig(config Config) Config {
|
||||
config.Values = append(json.RawMessage(nil), config.Values...)
|
||||
return config
|
||||
}
|
||||
|
||||
func (s *Store) Get(kind, provider string) (Config, bool) {
|
||||
if s == nil {
|
||||
return Config{}, false
|
||||
}
|
||||
s.mu.RLock()
|
||||
config, ok := s.values[configKey(kind, provider)]
|
||||
s.mu.RUnlock()
|
||||
return cloneConfig(config), ok
|
||||
}
|
||||
|
||||
func (s *Store) Set(config Config) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
config.Kind = strings.ToLower(strings.TrimSpace(config.Kind))
|
||||
config.Provider = strings.ToLower(strings.TrimSpace(config.Provider))
|
||||
config = cloneConfig(config)
|
||||
key := configKey(config.Kind, config.Provider)
|
||||
s.mu.Lock()
|
||||
s.values[key] = config
|
||||
callbacks := s.matchingListenersLocked(config.Kind, config.Provider)
|
||||
s.mu.Unlock()
|
||||
for _, callback := range callbacks {
|
||||
callback(cloneConfig(config))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Store) Delete(kind, provider string) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
kind = strings.ToLower(strings.TrimSpace(kind))
|
||||
provider = strings.ToLower(strings.TrimSpace(provider))
|
||||
s.mu.Lock()
|
||||
delete(s.values, configKey(kind, provider))
|
||||
callbacks := s.matchingListenersLocked(kind, provider)
|
||||
s.mu.Unlock()
|
||||
config := Config{Kind: kind, Provider: provider}
|
||||
for _, callback := range callbacks {
|
||||
callback(config)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Store) Replace(configs []Config) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
next := make(map[string]Config, len(configs))
|
||||
for _, config := range configs {
|
||||
config.Kind = strings.ToLower(strings.TrimSpace(config.Kind))
|
||||
config.Provider = strings.ToLower(strings.TrimSpace(config.Provider))
|
||||
config = cloneConfig(config)
|
||||
next[configKey(config.Kind, config.Provider)] = config
|
||||
}
|
||||
s.mu.Lock()
|
||||
previous := s.values
|
||||
s.values = next
|
||||
listeners := make([]listener, 0, len(s.listeners))
|
||||
for _, item := range s.listeners {
|
||||
listeners = append(listeners, item)
|
||||
}
|
||||
s.mu.Unlock()
|
||||
|
||||
changed := make(map[string]Config, len(previous)+len(next))
|
||||
for key, config := range previous {
|
||||
changed[key] = Config{Kind: config.Kind, Provider: config.Provider}
|
||||
}
|
||||
for key, config := range next {
|
||||
changed[key] = config
|
||||
}
|
||||
for _, item := range listeners {
|
||||
if config, ok := changed[configKey(item.kind, item.provider)]; ok {
|
||||
item.callback(cloneConfig(config))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Store) Subscribe(kind, provider string, callback func(Config)) func() {
|
||||
if s == nil || callback == nil {
|
||||
return func() {}
|
||||
}
|
||||
s.mu.Lock()
|
||||
s.nextID++
|
||||
id := s.nextID
|
||||
s.listeners[id] = listener{kind: strings.ToLower(strings.TrimSpace(kind)), provider: strings.ToLower(strings.TrimSpace(provider)), callback: callback}
|
||||
s.mu.Unlock()
|
||||
return func() {
|
||||
s.mu.Lock()
|
||||
delete(s.listeners, id)
|
||||
s.mu.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Store) matchingListenersLocked(kind, provider string) []func(Config) {
|
||||
callbacks := make([]func(Config), 0)
|
||||
for _, item := range s.listeners {
|
||||
if item.kind == kind && item.provider == provider {
|
||||
callbacks = append(callbacks, item.callback)
|
||||
}
|
||||
}
|
||||
return callbacks
|
||||
}
|
||||
Reference in New Issue
Block a user