From 05d2cda34040f242ce751c2c2b9dedf9ea2804e3 Mon Sep 17 00:00:00 2001 From: FZambia Date: Fri, 27 Sep 2024 14:40:12 +0300 Subject: [PATCH] proper defaults for array/map options --- internal/config/config_test.go | 2 +- internal/configtypes/namespace.go | 16 +++++ internal/configtypes/rpc_namespace.go | 19 ++++++ internal/configtypes/stringmap.go | 12 ++++ internal/configtypes/types.go | 97 +++++++++------------------ internal/gen/api/main.go | 14 +--- internal/proxy/grpc.go | 7 +- internal/proxy/http.go | 12 +--- 8 files changed, 87 insertions(+), 92 deletions(-) create mode 100644 internal/configtypes/stringmap.go diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 1a1388f24d..ff5219be0b 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -81,7 +81,7 @@ func TestConfigEnvVars(t *testing.T) { require.Len(t, meta.UnknownEnvs, 1) require.Len(t, meta.UnknownKeys, 0) require.Contains(t, meta.UnknownEnvs, "CENTRIFUGO_UNKNOWN_ENV") - require.Equal(t, configtypes.EnvStringStringMap(map[string]string{"key": "value"}), conf.UnifiedProxy.HTTP.StaticHeaders) + require.Equal(t, configtypes.MapStringString(map[string]string{"key": "value"}), conf.UnifiedProxy.HTTP.StaticHeaders) require.Equal(t, configtypes.Duration(300*time.Millisecond), conf.WebSocket.WriteTimeout) require.Len(t, conf.Proxies, 0) } diff --git a/internal/configtypes/namespace.go b/internal/configtypes/namespace.go index d455f040cf..964fb9d29d 100644 --- a/internal/configtypes/namespace.go +++ b/internal/configtypes/namespace.go @@ -1,11 +1,27 @@ package configtypes import ( + "encoding/json" + "fmt" "regexp" "github.com/centrifugal/centrifuge" ) +type ChannelNamespaces []ChannelNamespace + +// Decode to implement the envconfig.Decoder interface +func (d *ChannelNamespaces) Decode(value string) error { + // If the source is a string and the target is a slice, try to parse it as JSON. + var items ChannelNamespaces + err := json.Unmarshal([]byte(value), &items) + if err != nil { + return fmt.Errorf("error parsing items from JSON: %v", err) + } + *d = items + return nil +} + // ChannelNamespace allows creating channels with different channel options. type ChannelNamespace struct { // Name is a unique namespace name. diff --git a/internal/configtypes/rpc_namespace.go b/internal/configtypes/rpc_namespace.go index 25c50baa58..3fa43c4776 100644 --- a/internal/configtypes/rpc_namespace.go +++ b/internal/configtypes/rpc_namespace.go @@ -1,5 +1,24 @@ package configtypes +import ( + "encoding/json" + "fmt" +) + +type RPCNamespaces []RpcNamespace + +// Decode to implement the envconfig.Decoder interface +func (d *RPCNamespaces) Decode(value string) error { + // If the source is a string and the target is a slice, try to parse it as JSON. + var items RPCNamespaces + err := json.Unmarshal([]byte(value), &items) + if err != nil { + return fmt.Errorf("error parsing items from JSON: %v", err) + } + *d = items + return nil +} + // RpcNamespace allows creating rules for different rpc. type RpcNamespace struct { // Name is a unique rpc namespace name. diff --git a/internal/configtypes/stringmap.go b/internal/configtypes/stringmap.go new file mode 100644 index 0000000000..3dae6583dc --- /dev/null +++ b/internal/configtypes/stringmap.go @@ -0,0 +1,12 @@ +package configtypes + +import "encoding/json" + +type MapStringString map[string]string + +func (s *MapStringString) Decode(value string) error { + var m map[string]string + err := json.Unmarshal([]byte(value), &m) + *s = m + return err +} diff --git a/internal/configtypes/types.go b/internal/configtypes/types.go index 8458a924b6..1577120539 100644 --- a/internal/configtypes/types.go +++ b/internal/configtypes/types.go @@ -9,71 +9,6 @@ import ( "github.com/centrifugal/centrifuge" ) -type EnvStringStringMap map[string]string - -func (s *EnvStringStringMap) Decode(value string) error { - var m map[string]string - err := json.Unmarshal([]byte(value), &m) - *s = m - return err -} - -type ChannelNamespaces []ChannelNamespace - -// Decode to implement the envconfig.Decoder interface -func (d *ChannelNamespaces) Decode(value string) error { - // If the source is a string and the target is a slice, try to parse it as JSON. - var items ChannelNamespaces - err := json.Unmarshal([]byte(value), &items) - if err != nil { - return fmt.Errorf("error parsing items from JSON: %v", err) - } - *d = items - return nil -} - -type RPCNamespaces []RpcNamespace - -// Decode to implement the envconfig.Decoder interface -func (d *RPCNamespaces) Decode(value string) error { - // If the source is a string and the target is a slice, try to parse it as JSON. - var items RPCNamespaces - err := json.Unmarshal([]byte(value), &items) - if err != nil { - return fmt.Errorf("error parsing items from JSON: %v", err) - } - *d = items - return nil -} - -type Consumers []Consumer - -// Decode to implement the envconfig.Decoder interface -func (d *Consumers) Decode(value string) error { - // If the source is a string and the target is a slice, try to parse it as JSON. - var items Consumers - err := json.Unmarshal([]byte(value), &items) - if err != nil { - return fmt.Errorf("error parsing items from JSON: %v", err) - } - *d = items - return nil -} - -type Proxies []Proxy - -// Decode to implement the envconfig.Decoder interface -func (d *Proxies) Decode(value string) error { - // If the source is a string and the target is a slice, try to parse it as JSON. - var items Proxies - err := json.Unmarshal([]byte(value), &items) - if err != nil { - return fmt.Errorf("error parsing utems from JSON: %v", err) - } - *d = items - return nil -} - type Token struct { HMACSecretKey string `mapstructure:"hmac_secret_key" json:"hmac_secret_key" envconfig:"hmac_secret_key" yaml:"hmac_secret_key" toml:"hmac_secret_key"` RSAPublicKey string `mapstructure:"rsa_public_key" json:"rsa_public_key" envconfig:"rsa_public_key" yaml:"rsa_public_key" toml:"rsa_public_key"` @@ -214,7 +149,7 @@ type RawModeConfig struct { // In this case Centrifugo will replace all ":" symbols in channel name with "." before sending to Nats. // Broker keeps reverse mapping to the original channel to broadcast to proper channels when processing // messages received from Nats. - ChannelReplacements EnvStringStringMap `mapstructure:"channel_replacements" default:"{}" json:"channel_replacements" envconfig:"channel_replacements" yaml:"channel_replacements" toml:"channel_replacements"` + ChannelReplacements MapStringString `mapstructure:"channel_replacements" default:"{}" json:"channel_replacements" envconfig:"channel_replacements" yaml:"channel_replacements" toml:"channel_replacements"` // Prefix is a string that will be added to all channels when publishing messages to Nats, subscribing // to channels in Nats. It's also stripped from channel name when processing messages received from Nats. @@ -415,7 +350,7 @@ type ProxyCommonHTTP struct { // StaticHeaders is a static set of key/value pairs to attach to HTTP proxy request as // headers. Headers received from HTTP client request or metadata from GRPC client request // both have priority over values set in StaticHttpHeaders map. - StaticHeaders EnvStringStringMap `mapstructure:"static_headers" default:"{}" json:"static_headers" envconfig:"static_headers" yaml:"static_headers" toml:"static_headers"` + StaticHeaders MapStringString `mapstructure:"static_headers" default:"{}" json:"static_headers" envconfig:"static_headers" yaml:"static_headers" toml:"static_headers"` } type ProxyCommonGRPC struct { @@ -481,6 +416,20 @@ type Proxy struct { TestGrpcDialer func(context.Context, string) (net.Conn, error) `json:"-" yaml:"-" toml:"-"` } +type Proxies []Proxy + +// Decode to implement the envconfig.Decoder interface +func (d *Proxies) Decode(value string) error { + // If the source is a string and the target is a slice, try to parse it as JSON. + var items Proxies + err := json.Unmarshal([]byte(value), &items) + if err != nil { + return fmt.Errorf("error parsing utems from JSON: %v", err) + } + *d = items + return nil +} + const ( ConsumerTypePostgres = "postgresql" ConsumerTypeKafka = "kafka" @@ -507,6 +456,20 @@ type Consumer struct { Kafka KafkaConsumerConfig `mapstructure:"kafka" json:"kafka" envconfig:"kafka" yaml:"kafka" toml:"kafka"` } +type Consumers []Consumer + +// Decode to implement the envconfig.Decoder interface +func (d *Consumers) Decode(value string) error { + // If the source is a string and the target is a slice, try to parse it as JSON. + var items Consumers + err := json.Unmarshal([]byte(value), &items) + if err != nil { + return fmt.Errorf("error parsing items from JSON: %v", err) + } + *d = items + return nil +} + type PostgresConsumerConfig struct { DSN string `mapstructure:"dsn" json:"dsn" envconfig:"dsn" yaml:"dsn" toml:"dsn"` OutboxTableName string `mapstructure:"outbox_table_name" json:"outbox_table_name" envconfig:"outbox_table_name" yaml:"outbox_table_name" toml:"outbox_table_name"` diff --git a/internal/gen/api/main.go b/internal/gen/api/main.go index ca779bca95..b0fc9d33ee 100644 --- a/internal/gen/api/main.go +++ b/internal/gen/api/main.go @@ -3,6 +3,7 @@ package main import ( "bytes" "os" + "slices" "strings" "text/template" @@ -23,15 +24,6 @@ type TemplateData struct { RequestLower string } -func stringInSlice(a string, list []string) bool { - for _, b := range list { - if b == a { - return true - } - } - return false -} - func generateToFile(header, funcTmpl, outFile string, excludeRequests []string, includeRequests []string) { tmpl := template.Must(template.New("").Parse(funcTmpl)) @@ -39,10 +31,10 @@ func generateToFile(header, funcTmpl, outFile string, excludeRequests []string, buf.WriteString(header) for _, req := range gen.Requests { - if stringInSlice(req, excludeRequests) { + if slices.Contains(excludeRequests, req) { continue } - if len(includeRequests) > 0 && !stringInSlice(req, includeRequests) { + if len(includeRequests) > 0 && !slices.Contains(includeRequests, req) { continue } err := tmpl.Execute(&buf, TemplateData{ diff --git a/internal/proxy/grpc.go b/internal/proxy/grpc.go index e9f9fb3dbe..8fe7c3d7cd 100644 --- a/internal/proxy/grpc.go +++ b/internal/proxy/grpc.go @@ -5,6 +5,7 @@ import ( "fmt" "net/http" "net/url" + "slices" "strings" "github.com/centrifugal/centrifugo/v5/internal/middleware" @@ -89,7 +90,7 @@ func requestMetadata(ctx context.Context, allowedHeaders []string, allowedMetaKe requestMD := metadata.MD{} if headers, ok := middleware.GetHeadersFromContext(ctx); ok { for k, vv := range headers { - if stringInSlice(strings.ToLower(k), allowedHeaders) { + if slices.Contains(allowedHeaders, strings.ToLower(k)) { requestMD.Set(k, vv...) } } @@ -97,7 +98,7 @@ func requestMetadata(ctx context.Context, allowedHeaders []string, allowedMetaKe } md, _ := metadata.FromIncomingContext(ctx) for k, vv := range md { - if stringInSlice(k, allowedMetaKeys) { + if slices.Contains(allowedMetaKeys, k) { requestMD[k] = vv } } @@ -115,7 +116,7 @@ func requestHeaders(ctx context.Context, allowedHeaders []string, allowedMetaKey headers.Set("Content-Type", "application/json") md, _ := metadata.FromIncomingContext(ctx) for k, vv := range md { - if stringInSlice(k, allowedMetaKeys) { + if slices.Contains(allowedMetaKeys, k) { headers[k] = vv } } diff --git a/internal/proxy/http.go b/internal/proxy/http.go index 6cefb8458f..9493ea5612 100644 --- a/internal/proxy/http.go +++ b/internal/proxy/http.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "net/http" + "slices" "strings" "time" @@ -92,18 +93,9 @@ func getProxyHeader(allHeader http.Header, allowedHeaders []string, staticHeader func copyHeader(dst, src http.Header, extraHeaders []string) { for k, vv := range src { - if !stringInSlice(strings.ToLower(k), extraHeaders) { + if !slices.Contains(extraHeaders, strings.ToLower(k)) { continue } dst[k] = vv } } - -func stringInSlice(a string, list []string) bool { - for _, b := range list { - if b == a { - return true - } - } - return false -}