From 1a20a7d35f40bd9daab5b2f35dfb76f10109a2f1 Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Wed, 28 Feb 2024 08:03:36 -0500 Subject: [PATCH] refactor: define a cluster config with redis and etcd support --- config/cluster.go | 70 ++++++++++++++++++++++++++++++++++++++++++++++ config/config.go | 2 +- config/core.go | 1 + config/database.go | 6 ---- config/etcd.go | 15 ++++++++++ 5 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 config/cluster.go create mode 100644 config/etcd.go diff --git a/config/cluster.go b/config/cluster.go new file mode 100644 index 0000000..3e590c6 --- /dev/null +++ b/config/cluster.go @@ -0,0 +1,70 @@ +package config + +import ( + "errors" + "reflect" + + "github.com/mitchellh/mapstructure" +) + +type ClusterConfig struct { + Enabled bool `mapstructure:"enabled"` + Redis *RedisConfig `mapstructure:"redis"` + Etcd *EtcdConfig `mapstructure:"etcd"` +} + +type RedisConfig struct { + Address string `mapstructure:"address"` + Password string `mapstructure:"password"` + DB int `mapstructure:"db"` +} + +func (r *RedisConfig) Validate() error { + if r.Address == "" { + return errors.New("address is required") + } + return nil +} + +func clusterConfigHook() mapstructure.DecodeHookFuncType { + return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + if f.Kind() != reflect.Map || t != reflect.TypeOf(&ClusterConfig{}) { + return data, nil + } + + var clusterConfig ClusterConfig + if err := mapstructure.Decode(data, &clusterConfig); err != nil { + return nil, err + } + + // Check if the input data map includes "redis" configuration + if opts, ok := data.(map[string]interface{})["redis"].(map[string]interface{}); ok && opts != nil { + var redisOptions RedisConfig + if err := mapstructure.Decode(opts, &redisOptions); err != nil { + return nil, err + } + + if err := redisOptions.Validate(); err != nil { + return nil, err + } + + clusterConfig.Redis = &redisOptions + } + + // Check if the input data map includes "etcd" configuration + if opts, ok := data.(map[string]interface{})["etcd"].(map[string]interface{}); ok && opts != nil { + var etcdOptions EtcdConfig + if err := mapstructure.Decode(opts, &etcdOptions); err != nil { + return nil, err + } + + if err := etcdOptions.Validate(); err != nil { + return nil, err + } + + clusterConfig.Etcd = &etcdOptions + } + + return &clusterConfig, nil + } +} diff --git a/config/config.go b/config/config.go index 50e2f79..ac3184f 100644 --- a/config/config.go +++ b/config/config.go @@ -47,7 +47,7 @@ func NewManager() (*Manager, error) { return nil, err } - err = v.Unmarshal(&config, viper.DecodeHook(cacheConfigHook())) + err = v.Unmarshal(&config, viper.DecodeHook(clusterConfigHook()), viper.DecodeHook(cacheConfigHook())) if err != nil { return nil, err } diff --git a/config/core.go b/config/core.go index 15eaf9b..5037938 100644 --- a/config/core.go +++ b/config/core.go @@ -13,4 +13,5 @@ type CoreConfig struct { Storage StorageConfig `mapstructure:"storage"` Protocols []string `mapstructure:"protocols"` Mail MailConfig `mapstructure:"mail"` + Clustered *ClusterConfig `mapstructure:"clustered"` } diff --git a/config/database.go b/config/database.go index 47f1ce1..4581f32 100644 --- a/config/database.go +++ b/config/database.go @@ -21,12 +21,6 @@ type CacheConfig struct { Options interface{} `mapstructure:"options"` } -type RedisConfig struct { - Address string `mapstructure:"address"` - Password string `mapstructure:"password"` - DB int `mapstructure:"db"` -} - type MemoryConfig struct { } diff --git a/config/etcd.go b/config/etcd.go new file mode 100644 index 0000000..01a9957 --- /dev/null +++ b/config/etcd.go @@ -0,0 +1,15 @@ +package config + +import "errors" + +type EtcdConfig struct { + Endpoints []string `mapstructure:"endpoints"` + DialTimeout int `mapstructure:"dial_timeout"` +} + +func (r *EtcdConfig) Validate() error { + if len(r.Endpoints) == 0 { + return errors.New("endpoints is required") + } + return nil +}