You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kratos/filter/httpcache/configuration.go

340 lines
9.6 KiB

2 years ago
package httpcache
import (
"regexp"
"time"
"github.com/darkweak/souin/configurationtypes"
"github.com/darkweak/souin/plugins"
"github.com/go-kratos/kratos/v2/config"
)
const (
configurationKey = "httpcache"
path = "path"
url = "url"
configurationPK = "configuration"
)
func parseRecursively(values map[string]config.Value) map[string]interface{} {
result := make(map[string]interface{})
for key, value := range values {
if v, e := value.Bool(); e == nil {
result[key] = v
continue
}
switch value.Load().(type) {
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
if v, e := value.Int(); e == nil {
result[key] = v
continue
}
case float32, float64:
if v, e := value.Float(); e == nil {
result[key] = v
continue
}
}
svalue, _ := value.String()
if v, e := time.ParseDuration(svalue); e == nil {
result[key] = v
continue
}
if v, e := value.Map(); e == nil {
result[key] = parseRecursively(v)
continue
}
}
return result
}
func parseAPI(apiConfiguration map[string]config.Value) configurationtypes.API {
var a configurationtypes.API
var prometheusConfiguration, souinConfiguration map[string]config.Value
for apiK, apiV := range apiConfiguration {
switch apiK {
case "prometheus":
prometheusConfiguration, _ = apiV.Map()
case "souin":
souinConfiguration, _ = apiV.Map()
}
}
if prometheusConfiguration != nil {
a.Prometheus = configurationtypes.APIEndpoint{}
a.Prometheus.Enable = true
if prometheusConfiguration["basepath"] != nil {
a.Prometheus.BasePath, _ = prometheusConfiguration["basepath"].String()
}
}
if souinConfiguration != nil {
a.Souin = configurationtypes.APIEndpoint{}
a.Souin.Enable = true
if souinConfiguration["basepath"] != nil {
a.Souin.BasePath, _ = souinConfiguration["basepath"].String()
}
}
return a
}
func parseCacheKeys(ccConfiguration map[string]config.Value) map[configurationtypes.RegValue]configurationtypes.Key {
cacheKeys := make(map[configurationtypes.RegValue]configurationtypes.Key)
for cacheKeysConfigurationK, cacheKeysConfigurationV := range ccConfiguration {
ck := configurationtypes.Key{}
cacheKeysConfigurationVMap, _ := cacheKeysConfigurationV.Map()
for cacheKeysConfigurationVMapK := range cacheKeysConfigurationVMap {
switch cacheKeysConfigurationVMapK {
case "disable_body":
ck.DisableBody = true
case "disable_host":
ck.DisableHost = true
case "disable_method":
ck.DisableMethod = true
}
}
rg := regexp.MustCompile(cacheKeysConfigurationK)
cacheKeys[configurationtypes.RegValue{Regexp: rg}] = ck
}
return cacheKeys
}
func parseDefaultCache(dcConfiguration map[string]config.Value) *configurationtypes.DefaultCache {
dc := configurationtypes.DefaultCache{
Distributed: false,
Headers: []string{},
Olric: configurationtypes.CacheProvider{
URL: "",
Path: "",
Configuration: nil,
},
Regex: configurationtypes.Regex{},
TTL: configurationtypes.Duration{},
DefaultCacheControl: "",
}
for defaultCacheK, defaultCacheV := range dcConfiguration {
switch defaultCacheK {
case "allowed_http_verbs":
headers, _ := defaultCacheV.Slice()
dc.AllowedHTTPVerbs = make([]string, 0)
for _, header := range headers {
h, _ := header.String()
dc.AllowedHTTPVerbs = append(dc.AllowedHTTPVerbs, h)
}
case "badger":
provider := configurationtypes.CacheProvider{}
badgerConfiguration, _ := defaultCacheV.Map()
for badgerConfigurationK, badgerConfigurationV := range badgerConfiguration {
switch badgerConfigurationK {
case url:
provider.URL, _ = badgerConfigurationV.String()
case path:
provider.Path, _ = badgerConfigurationV.String()
case configurationPK:
configMap, e := badgerConfigurationV.Map()
if e == nil {
provider.Configuration = parseRecursively(configMap)
}
}
}
dc.Badger = provider
case "cdn":
cdn := configurationtypes.CDN{}
cdnConfiguration, _ := defaultCacheV.Map()
for cdnConfigurationK, cdnConfigurationV := range cdnConfiguration {
switch cdnConfigurationK {
case "api_key":
cdn.APIKey, _ = cdnConfigurationV.String()
case "dynamic":
cdn.Dynamic = true
case "hostname":
cdn.Hostname, _ = cdnConfigurationV.String()
case "network":
cdn.Network, _ = cdnConfigurationV.String()
case "provider":
cdn.Provider, _ = cdnConfigurationV.String()
case "strategy":
cdn.Strategy, _ = cdnConfigurationV.String()
}
}
dc.CDN = cdn
case "etcd":
provider := configurationtypes.CacheProvider{}
etcdConfiguration, _ := defaultCacheV.Map()
for etcdConfigurationK, etcdConfigurationV := range etcdConfiguration {
switch etcdConfigurationK {
case url:
provider.URL, _ = etcdConfigurationV.String()
case path:
provider.Path, _ = etcdConfigurationV.String()
case configurationPK:
configMap, e := etcdConfigurationV.Map()
if e == nil {
provider.Configuration = parseRecursively(configMap)
}
}
}
dc.Etcd = provider
case "headers":
headers, _ := defaultCacheV.Slice()
dc.Headers = make([]string, 0)
for _, header := range headers {
h, _ := header.String()
dc.Headers = append(dc.Headers, h)
}
case "nuts":
provider := configurationtypes.CacheProvider{}
nutsConfiguration, _ := defaultCacheV.Map()
for nutsConfigurationK, nutsConfigurationV := range nutsConfiguration {
switch nutsConfigurationK {
case url:
provider.URL, _ = nutsConfigurationV.String()
case path:
provider.Path, _ = nutsConfigurationV.String()
case configurationPK:
configMap, e := nutsConfigurationV.Map()
if e == nil {
provider.Configuration = parseRecursively(configMap)
}
}
}
dc.Nuts = provider
case "olric":
provider := configurationtypes.CacheProvider{}
olricConfiguration, _ := defaultCacheV.Map()
for olricConfigurationK, olricConfigurationV := range olricConfiguration {
switch olricConfigurationK {
case url:
provider.URL, _ = olricConfigurationV.String()
case path:
provider.Path, _ = olricConfigurationV.String()
case configurationPK:
configMap, e := olricConfigurationV.Map()
if e == nil {
provider.Configuration = parseRecursively(configMap)
}
}
}
dc.Distributed = true
dc.Olric = provider
case "regex":
regex, _ := defaultCacheV.Map()
exclude, _ := regex["exclude"].String()
if exclude != "" {
dc.Regex = configurationtypes.Regex{Exclude: exclude}
}
case "ttl":
sttl, err := defaultCacheV.String()
ttl, _ := time.ParseDuration(sttl)
if err == nil {
dc.TTL = configurationtypes.Duration{Duration: ttl}
}
case "stale":
sstale, err := defaultCacheV.String()
stale, _ := time.ParseDuration(sstale)
if err == nil {
dc.Stale = configurationtypes.Duration{Duration: stale}
}
case "default_cache_control":
dc.DefaultCacheControl, _ = defaultCacheV.String()
}
}
return &dc
}
func parseURLs(urls map[string]config.Value) map[string]configurationtypes.URL {
u := make(map[string]configurationtypes.URL)
for urlK, urlV := range urls {
currentURL := configurationtypes.URL{
TTL: configurationtypes.Duration{},
Headers: nil,
}
currentValue, _ := urlV.Map()
if currentValue["headers"] != nil {
currentURL.Headers = make([]string, 0)
headers, _ := currentValue["headers"].Slice()
for _, header := range headers {
h, _ := header.String()
currentURL.Headers = append(currentURL.Headers, h)
}
}
sttl, err := currentValue["ttl"].String()
ttl, _ := time.ParseDuration(sttl)
if err == nil {
currentURL.TTL = configurationtypes.Duration{Duration: ttl}
}
if _, exists := currentValue["default_cache_control"]; exists {
currentURL.DefaultCacheControl, _ = currentValue["default_cache_control"].String()
}
u[urlK] = currentURL
}
return u
}
func parseSurrogateKeys(surrogates map[string]config.Value) map[string]configurationtypes.SurrogateKeys {
u := make(map[string]configurationtypes.SurrogateKeys)
for surrogateK, surrogateV := range surrogates {
surrogate := configurationtypes.SurrogateKeys{}
currentValue, _ := surrogateV.Map()
for key, value := range currentValue {
switch key {
case "headers":
surrogate.Headers = map[string]string{}
headers, e := value.Map()
if e == nil {
for hKey, hValue := range headers {
v, _ := hValue.String()
surrogate.Headers[hKey] = v
}
}
case "url":
surl, _ := currentValue["url"].String()
surrogate.URL = surl
}
}
u[surrogateK] = surrogate
}
return u
}
// ParseConfiguration parse the Kratos configuration into a valid HTTP
// cache configuration object.
func ParseConfiguration(c config.Config) plugins.BaseConfiguration {
var configuration plugins.BaseConfiguration
values, _ := c.Value(configurationKey).Map()
for key, v := range values {
switch key {
case "api":
apiConfiguration, _ := v.Map()
configuration.API = parseAPI(apiConfiguration)
case "cache_keys":
cacheKeysConfiguration, _ := v.Map()
configuration.CacheKeys = parseCacheKeys(cacheKeysConfiguration)
case "default_cache":
defaultCache, _ := v.Map()
configuration.DefaultCache = parseDefaultCache(defaultCache)
case "log_level":
configuration.LogLevel, _ = v.String()
case "urls":
urls, _ := v.Map()
configuration.URLs = parseURLs(urls)
case "ykeys":
ykeys, _ := v.Map()
configuration.Ykeys = parseSurrogateKeys(ykeys)
case "surrogate_keys":
surrogates, _ := v.Map()
configuration.SurrogateKeys = parseSurrogateKeys(surrogates)
}
}
return configuration
}