1
0
Fork 0
mirror of https://github.com/alice-lg/birdwatcher.git synced 2025-03-09 00:00:05 +01:00
birdwatcher/bird/redis_cache.go

114 lines
2.4 KiB
Go
Raw Permalink Normal View History

2019-01-24 17:15:17 +01:00
package bird
import (
2020-10-28 15:42:16 +01:00
"context"
2019-01-24 17:15:17 +01:00
"encoding/json"
2020-10-28 15:48:21 +01:00
"fmt"
"log"
2019-01-24 17:15:17 +01:00
"time"
2020-10-28 15:42:16 +01:00
"github.com/go-redis/redis/v8"
2019-01-24 17:15:17 +01:00
)
type RedisCache struct {
client *redis.Client
keyPrefix string
2019-01-24 17:15:17 +01:00
}
func NewRedisCache(config CacheConfig) (*RedisCache, error) {
client := redis.NewClient(&redis.Options{
Addr: config.RedisServer,
Password: config.RedisPassword,
DB: config.RedisDb,
})
2020-10-28 15:42:16 +01:00
ctx := context.Background()
_, err := client.Ping(ctx).Result()
2019-01-24 17:15:17 +01:00
if err != nil {
return nil, err
}
cache := &RedisCache{
client: client,
}
return cache, nil
}
2020-10-28 15:48:21 +01:00
// Get retrievs a birdwatcher `Parsed` result from
// the redis cache.
2019-01-24 17:15:17 +01:00
func (self *RedisCache) Get(key string) (Parsed, error) {
2020-10-28 15:42:16 +01:00
ctx := context.Background()
key = self.keyPrefix + key //"B" + IPVersion + "_" + key
2020-10-28 15:42:16 +01:00
data, err := self.client.Get(ctx, key).Result()
2019-01-24 17:15:17 +01:00
if err != nil {
return NilParse, err
}
parsed := Parsed{}
err = json.Unmarshal([]byte(data), &parsed)
2020-10-28 16:03:22 +01:00
ttl, err := parseCacheTTL(parsed["ttl"])
if err != nil {
2020-10-28 15:48:21 +01:00
return NilParse, fmt.Errorf("invalid TTL value for key: %s", key)
}
2020-10-28 16:13:58 +01:00
// Deal with the inband TTL if present
if !ttl.Equal(time.Time{}) && ttl.Before(time.Now()) {
return NilParse, err // TTL expired
}
2020-10-28 15:48:21 +01:00
return parsed, err // cache hit
2019-01-24 17:15:17 +01:00
}
2020-10-28 15:48:21 +01:00
// Set adds a birdwatcher `Parsed` result
// to the redis cache.
func (self *RedisCache) Set(key string, parsed Parsed, ttl int) error {
switch {
case ttl == 0:
return nil // do not cache
case ttl > 0:
key = self.keyPrefix + key //TODO "B" + IPVersion + "_" + key
payload, err := json.Marshal(parsed)
if err != nil {
return err
}
2020-10-28 15:42:16 +01:00
ctx := context.Background()
_, err = self.client.Set(
ctx, key, payload, time.Duration(ttl)*time.Minute).Result()
2019-01-24 17:15:17 +01:00
return err
default: // ttl negative - invalid
2020-10-28 15:48:21 +01:00
return fmt.Errorf("negative TTL value for key: %s", key)
}
2019-01-24 17:15:17 +01:00
}
func (self *RedisCache) Expire() int {
log.Printf("Cannot expire entries in RedisCache backend, redis does this automatically")
return 0
}
2020-10-28 16:03:22 +01:00
// Helperfunction to decode the cache ttl stored
// in the cache - which will most likely just be
// RFC3339 timestamp.
func parseCacheTTL(cacheTTL interface{}) (time.Time, error) {
if cacheTTL == nil {
// We preseve the nil value as a zero value
return time.Time{}, nil
}
switch cacheTTL.(type) {
case string:
ttl, err := time.Parse(time.RFC3339, cacheTTL.(string))
if err != nil {
return time.Time{}, err
}
return ttl, nil
case time.Time:
return cacheTTL.(time.Time), nil
}
return time.Time{}, nil
}