mirror of
https://github.com/alice-lg/birdwatcher.git
synced 2025-03-09 00:00:05 +01:00
113 lines
2.4 KiB
Go
113 lines
2.4 KiB
Go
package bird
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"time"
|
|
|
|
"github.com/go-redis/redis/v8"
|
|
)
|
|
|
|
type RedisCache struct {
|
|
client *redis.Client
|
|
keyPrefix string
|
|
}
|
|
|
|
func NewRedisCache(config CacheConfig) (*RedisCache, error) {
|
|
|
|
client := redis.NewClient(&redis.Options{
|
|
Addr: config.RedisServer,
|
|
Password: config.RedisPassword,
|
|
DB: config.RedisDb,
|
|
})
|
|
|
|
ctx := context.Background()
|
|
_, err := client.Ping(ctx).Result()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
cache := &RedisCache{
|
|
client: client,
|
|
}
|
|
|
|
return cache, nil
|
|
}
|
|
|
|
// Get retrievs a birdwatcher `Parsed` result from
|
|
// the redis cache.
|
|
func (self *RedisCache) Get(key string) (Parsed, error) {
|
|
ctx := context.Background()
|
|
key = self.keyPrefix + key //"B" + IPVersion + "_" + key
|
|
data, err := self.client.Get(ctx, key).Result()
|
|
if err != nil {
|
|
return NilParse, err
|
|
}
|
|
|
|
parsed := Parsed{}
|
|
err = json.Unmarshal([]byte(data), &parsed)
|
|
|
|
ttl, err := parseCacheTTL(parsed["ttl"])
|
|
if err != nil {
|
|
return NilParse, fmt.Errorf("invalid TTL value for key: %s", key)
|
|
}
|
|
// Deal with the inband TTL if present
|
|
if !ttl.Equal(time.Time{}) && ttl.Before(time.Now()) {
|
|
return NilParse, err // TTL expired
|
|
}
|
|
|
|
return parsed, err // cache hit
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
ctx := context.Background()
|
|
_, err = self.client.Set(
|
|
ctx, key, payload, time.Duration(ttl)*time.Minute).Result()
|
|
return err
|
|
|
|
default: // ttl negative - invalid
|
|
return fmt.Errorf("negative TTL value for key: %s", key)
|
|
}
|
|
}
|
|
|
|
func (self *RedisCache) Expire() int {
|
|
log.Printf("Cannot expire entries in RedisCache backend, redis does this automatically")
|
|
return 0
|
|
}
|
|
|
|
// 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
|
|
}
|