// SPDX-FileCopyrightText: 2022 Free Mobile // SPDX-License-Identifier: AGPL-3.0-only package httpserver import ( "context" "fmt" "runtime" "time" "akvorado/common/helpers" "github.com/chenyahui/gin-cache/persist" "github.com/go-redis/redis/v8" ) // Configuration describes the configuration for the HTTP server. type Configuration struct { // Listen defines the listening string to listen to. Listen string `validate:"required,listen"` // Profiler enables Go profiler as /debug Profiler bool // Cache configuration Cache CacheConfiguration } // CacheConfiguration describes the configuration of the internal HTTP cache. // Currently, it delegates everything to the implemented backends. type CacheConfiguration struct { // Config is the backend-specific configuration for the cache Config CacheBackendConfiguration } // CacheBackendConfiguration represents the configuration of a cache backend. type CacheBackendConfiguration interface { New() (persist.CacheStore, error) } // MemoryCacheConfiguration is the configuration for an in-memory cache. There // is no configuration. type MemoryCacheConfiguration struct{} // New creates a new memory cache store from a memory cache configuration. func (MemoryCacheConfiguration) New() (persist.CacheStore, error) { return persist.NewMemoryStore(5 * time.Minute), nil } // DefaultMemoryCacheConfiguration returns the default configuration for an // in-memory cache. func DefaultMemoryCacheConfiguration() CacheBackendConfiguration { return MemoryCacheConfiguration{} } // RedisCacheConfiguration is the configuration for a Redis cache. type RedisCacheConfiguration struct { // Protocol to connect with Protocol string `validate:"oneof=tcp unix"` // Server to connect to (with port) Server string `validate:"required,listen"` // Optional username Username string // Optional password Password string // Database to connect to DB int } // New creates a new Redis cache store from a Redis cache configuration. func (c RedisCacheConfiguration) New() (persist.CacheStore, error) { client := redis.NewClient(&redis.Options{ Network: c.Protocol, Addr: c.Server, Username: c.Username, Password: c.Password, DB: c.DB, }) store := persist.NewRedisStore(client) runtime.SetFinalizer(store, func(*persist.RedisStore) { client.Close() }) if _, err := client.Ping(context.Background()).Result(); err != nil { return nil, fmt.Errorf("cannot ping Redis server: %w", err) } return store, nil } // DefaultRedisCacheConfiguration returns the default configuration for a // Redis-backed cache. func DefaultRedisCacheConfiguration() CacheBackendConfiguration { return RedisCacheConfiguration{ Protocol: "tcp", Server: "127.0.0.1:6379", } } // DefaultConfiguration is the default configuration of the HTTP server. func DefaultConfiguration() Configuration { return Configuration{ Listen: ":8080", Profiler: true, Cache: CacheConfiguration{ Config: DefaultMemoryCacheConfiguration(), }, } } // MarshalYAML undoes ConfigurationUnmarshallerHook(). func (cc CacheConfiguration) MarshalYAML() (any, error) { return helpers.ParametrizedConfigurationMarshalYAML(cc, cacheConfigurationMap) } var cacheConfigurationMap = map[string](func() CacheBackendConfiguration){ "memory": DefaultMemoryCacheConfiguration, "redis": DefaultRedisCacheConfiguration, } func init() { helpers.RegisterMapstructureUnmarshallerHook( helpers.ParametrizedConfigurationUnmarshallerHook(CacheConfiguration{}, cacheConfigurationMap)) }