From ccc9e6c19ad35aa17ceb3998145d12623afc9fdb Mon Sep 17 00:00:00 2001 From: andig Date: Fri, 2 Aug 2024 17:23:19 +0200 Subject: [PATCH] chore: add generic registry with context support (#15203) --- charger/config.go | 24 ++++++------------- meter/config.go | 24 ++++++------------- tariff/config.go | 24 ++++++------------- util/registry/registry.go | 49 +++++++++++++++++++++++++++++++++++++++ vehicle/config.go | 31 +++++-------------------- 5 files changed, 76 insertions(+), 76 deletions(-) create mode 100644 util/registry/registry.go diff --git a/charger/config.go b/charger/config.go index 0c0617ea3..2dcc7e687 100644 --- a/charger/config.go +++ b/charger/config.go @@ -1,31 +1,21 @@ package charger import ( + "context" "fmt" "strings" "github.com/evcc-io/evcc/api" + reg "github.com/evcc-io/evcc/util/registry" ) -type chargerRegistry map[string]func(map[string]interface{}) (api.Charger, error) +var registry = reg.New[api.Charger]("charger") -func (r chargerRegistry) Add(name string, factory func(map[string]interface{}) (api.Charger, error)) { - if _, exists := r[name]; exists { - panic(fmt.Sprintf("cannot register duplicate charger type: %s", name)) - } - r[name] = factory +// Types returns the list of types +func Types() []string { + return registry.Types() } -func (r chargerRegistry) Get(name string) (func(map[string]interface{}) (api.Charger, error), error) { - factory, exists := r[name] - if !exists { - return nil, fmt.Errorf("invalid charger type: %s", name) - } - return factory, nil -} - -var registry chargerRegistry = make(map[string]func(map[string]interface{}) (api.Charger, error)) - // NewFromConfig creates charger from configuration func NewFromConfig(typ string, other map[string]interface{}) (api.Charger, error) { factory, err := registry.Get(strings.ToLower(typ)) @@ -33,7 +23,7 @@ func NewFromConfig(typ string, other map[string]interface{}) (api.Charger, error return nil, err } - v, err := factory(other) + v, err := factory(context.TODO(), other) if err != nil { err = fmt.Errorf("cannot create charger type '%s': %w", typ, err) } diff --git a/meter/config.go b/meter/config.go index 68555c6b0..3a1228994 100644 --- a/meter/config.go +++ b/meter/config.go @@ -1,31 +1,21 @@ package meter import ( + "context" "fmt" "strings" "github.com/evcc-io/evcc/api" + reg "github.com/evcc-io/evcc/util/registry" ) -type meterRegistry map[string]func(map[string]interface{}) (api.Meter, error) +var registry = reg.New[api.Meter]("meter") -func (r meterRegistry) Add(name string, factory func(map[string]interface{}) (api.Meter, error)) { - if _, exists := r[name]; exists { - panic(fmt.Sprintf("cannot register duplicate meter type: %s", name)) - } - r[name] = factory +// Types returns the list of types +func Types() []string { + return registry.Types() } -func (r meterRegistry) Get(name string) (func(map[string]interface{}) (api.Meter, error), error) { - factory, exists := r[name] - if !exists { - return nil, fmt.Errorf("invalid meter type: %s", name) - } - return factory, nil -} - -var registry meterRegistry = make(map[string]func(map[string]interface{}) (api.Meter, error)) - // NewFromConfig creates meter from configuration func NewFromConfig(typ string, other map[string]interface{}) (api.Meter, error) { factory, err := registry.Get(strings.ToLower(typ)) @@ -33,7 +23,7 @@ func NewFromConfig(typ string, other map[string]interface{}) (api.Meter, error) return nil, err } - v, err := factory(other) + v, err := factory(context.TODO(), other) if err != nil { err = fmt.Errorf("cannot create meter type '%s': %w", typ, err) } diff --git a/tariff/config.go b/tariff/config.go index 34dda811b..a1cc7a945 100644 --- a/tariff/config.go +++ b/tariff/config.go @@ -1,31 +1,21 @@ package tariff import ( + "context" "fmt" "strings" "github.com/evcc-io/evcc/api" + reg "github.com/evcc-io/evcc/util/registry" ) -type tariffRegistry map[string]func(map[string]interface{}) (api.Tariff, error) +var registry = reg.New[api.Tariff]("tariff") -func (r tariffRegistry) Add(name string, factory func(map[string]interface{}) (api.Tariff, error)) { - if _, exists := r[name]; exists { - panic(fmt.Sprintf("cannot register duplicate tariff type: %s", name)) - } - r[name] = factory +// Types returns the list of types +func Types() []string { + return registry.Types() } -func (r tariffRegistry) Get(name string) (func(map[string]interface{}) (api.Tariff, error), error) { - factory, exists := r[name] - if !exists { - return nil, fmt.Errorf("invalid tariff type: %s", name) - } - return factory, nil -} - -var registry tariffRegistry = make(map[string]func(map[string]interface{}) (api.Tariff, error)) - // NewFromConfig creates tariff from configuration func NewFromConfig(typ string, other map[string]interface{}) (api.Tariff, error) { factory, err := registry.Get(strings.ToLower(typ)) @@ -33,7 +23,7 @@ func NewFromConfig(typ string, other map[string]interface{}) (api.Tariff, error) return nil, err } - v, err := factory(other) + v, err := factory(context.TODO(), other) if err != nil { err = fmt.Errorf("cannot create tariff type '%s': %w", typ, err) } diff --git a/util/registry/registry.go b/util/registry/registry.go new file mode 100644 index 000000000..3394f1b35 --- /dev/null +++ b/util/registry/registry.go @@ -0,0 +1,49 @@ +package registry + +import ( + "context" + "fmt" + + "golang.org/x/exp/maps" +) + +type ( + factoryFunc[T any] func(context.Context, map[string]any) (T, error) + + registry[T any] struct { + typ string + data map[string]factoryFunc[T] + } +) + +func (r registry[T]) Add(name string, factory func(map[string]any) (T, error)) { + r.AddCtx(name, func(_ context.Context, cc map[string]any) (T, error) { + return factory(cc) + }) +} + +func (r registry[T]) AddCtx(name string, factory factoryFunc[T]) { + if _, exists := r.data[name]; exists { + panic(fmt.Sprintf("cannot register duplicate %s type: %s", r.typ, name)) + } + r.data[name] = factory +} + +func (r registry[T]) Get(name string) (factoryFunc[T], error) { + factory, exists := r.data[name] + if !exists { + return nil, fmt.Errorf("invalid %s type: %s", r.typ, name) + } + return factory, nil +} + +func (r registry[T]) Types() []string { + return maps.Keys(r.data) +} + +func New[T any](typ string) registry[T] { + return registry[T]{ + typ: typ, + data: make(map[string]factoryFunc[T]), + } +} diff --git a/vehicle/config.go b/vehicle/config.go index ca692e59a..2590013d0 100644 --- a/vehicle/config.go +++ b/vehicle/config.go @@ -1,12 +1,14 @@ package vehicle import ( + "context" "fmt" "strings" "time" "github.com/evcc-io/evcc/api" "github.com/evcc-io/evcc/util" + reg "github.com/evcc-io/evcc/util/registry" ) const ( @@ -14,32 +16,11 @@ const ( interval = 15 * time.Minute // refresh interval when charging ) -type vehicleRegistry map[string]func(map[string]interface{}) (api.Vehicle, error) +var registry = reg.New[api.Vehicle]("vehicle") -func (r vehicleRegistry) Add(name string, factory func(map[string]interface{}) (api.Vehicle, error)) { - if _, exists := r[name]; exists { - panic(fmt.Sprintf("cannot register duplicate vehicle type: %s", name)) - } - r[name] = factory -} - -func (r vehicleRegistry) Get(name string) (func(map[string]interface{}) (api.Vehicle, error), error) { - factory, exists := r[name] - if !exists { - return nil, fmt.Errorf("invalid vehicle type: %s", name) - } - return factory, nil -} - -var registry vehicleRegistry = make(map[string]func(map[string]interface{}) (api.Vehicle, error)) - -// Types returns the list of vehicle types +// Types returns the list of types func Types() []string { - var res []string - for typ := range registry { - res = append(res, typ) - } - return res + return registry.Types() } // NewFromConfig creates vehicle from configuration @@ -63,7 +44,7 @@ func NewFromConfig(typ string, other map[string]interface{}) (api.Vehicle, error return nil, err } - v, err := factory(cc.Other) + v, err := factory(context.TODO(), cc.Other) if err != nil { err = fmt.Errorf("cannot create vehicle type '%s': %w", typ, err) }