Files
crowdsec-bouncer-traefik-pl…/pkg/cache/cache.go
T
maxlerebourgandGitHub 575d3a02e5 Add a logger instance to bouncer instance (#134)
*  Add a logger instance to bouncer instance

* 🍱 fix test

* 🍱 fix lint

* 🍱 fix lint

* 🍱 fix lint

* 🍱 fix lint

* 🍱 fix lint

* 🍱 fix test

* 🍱 fix test

* 🍱 fix lint + test

* 🍱 fix test

* 🍱 fix test

* 🍱 fix test

* 🍱 fix lint

* 🍱 fix lint
2024-02-11 11:52:47 +01:00

123 lines
3.3 KiB
Go

// Package cache implements utility routines for manipulating cache.
// It supports currently local file and redis cache.
package cache
import (
"fmt"
ttl_map "github.com/leprosus/golang-ttl-map"
simpleredis "github.com/maxlerebourg/simpleredis"
logger "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin/pkg/logger"
)
const (
cacheBannedValue = "t"
cacheNoBannedValue = "f"
)
// CacheMiss error string when cache is miss.
const CacheMiss = "cache:miss"
//nolint:gochecknoglobals
var (
redis simpleredis.SimpleRedis
cache = ttl_map.New()
)
type localCache struct{}
func (localCache) getDecision(clientIP string) (bool, error) {
banned, isCached := cache.Get(clientIP)
bannedString, isValid := banned.(string)
if isCached && isValid && len(bannedString) > 0 {
return bannedString == cacheBannedValue, nil
}
return false, fmt.Errorf(CacheMiss)
}
func (localCache) setDecision(clientIP string, value string, duration int64) {
cache.Set(clientIP, value, duration)
}
func (localCache) deleteDecision(clientIP string) {
cache.Del(clientIP)
}
type redisCache struct {
log *logger.Log
}
func (redisCache) getDecision(clientIP string) (bool, error) {
banned, err := redis.Get(clientIP)
bannedString := string(banned)
if err == nil && len(bannedString) > 0 {
return bannedString == cacheBannedValue, nil
}
if err.Error() == simpleredis.RedisMiss {
return false, fmt.Errorf(CacheMiss)
}
return false, err
}
func (rc redisCache) setDecision(clientIP string, value string, duration int64) {
if err := redis.Set(clientIP, []byte(value), duration); err != nil {
rc.log.Error(fmt.Sprintf("cache:setDecisionRedisCache %s", err.Error()))
}
}
func (rc redisCache) deleteDecision(clientIP string) {
if err := redis.Del(clientIP); err != nil {
rc.log.Error(fmt.Sprintf("cache:deleteDecisionRedisCache %s", err.Error()))
}
}
type cacheInterface interface {
setDecision(clientIP string, value string, duration int64)
getDecision(clientIP string) (bool, error)
deleteDecision(clientIP string)
}
// Client Cache client.
type Client struct {
cache cacheInterface
log *logger.Log
}
// Init Initialize cache client.
func (c *Client) Init(log *logger.Log, isRedis bool, host, pass, database string) {
c.log = log
if isRedis {
redis.Init(host, pass, database)
c.cache = &redisCache{log: log}
} else {
c.cache = &localCache{}
}
c.log.Debug(fmt.Sprintf("cache:New initialized isRedis:%v", isRedis))
}
// DeleteDecision delete decision in cache.
func (c *Client) DeleteDecision(clientIP string) {
c.log.Debug(fmt.Sprintf("cache:DeleteDecision ip:%v", clientIP))
c.cache.deleteDecision(clientIP)
}
// GetDecision check in the cache if the IP has the banned / not banned value.
// Otherwise return with an error to add the IP in cache if we are on.
func (c *Client) GetDecision(clientIP string) (bool, error) {
c.log.Debug(fmt.Sprintf("cache:GetDecision ip:%v", clientIP))
return c.cache.getDecision(clientIP)
}
// SetDecision update the cache with the IP as key and the value banned / not banned.
func (c *Client) SetDecision(clientIP string, isBanned bool, duration int64) {
c.log.Debug(fmt.Sprintf("cache:SetDecision ip:%v isBanned:%v duration:%vs", clientIP, isBanned, duration))
var value string
if isBanned {
value = cacheBannedValue
} else {
value = cacheNoBannedValue
}
c.cache.setDecision(clientIP, value, duration)
}