From 7c6464b0f733d05cc39fb7087140dc326923fbc3 Mon Sep 17 00:00:00 2001 From: Christine Dodrill Date: Sat, 27 Jan 2018 15:38:18 -0800 Subject: [PATCH] internal/database: start redis driver --- internal/database/boltdb.go | 2 + internal/database/redis.go | 151 ++++++++++++++++++++++++++++++++ internal/database/redis_test.go | 31 +++++++ 3 files changed, 184 insertions(+) create mode 100644 internal/database/redis.go create mode 100644 internal/database/redis_test.go diff --git a/internal/database/boltdb.go b/internal/database/boltdb.go index 16807d7..8daa97a 100644 --- a/internal/database/boltdb.go +++ b/internal/database/boltdb.go @@ -125,6 +125,8 @@ func (b *boltRouteStorage) GetAll(ctx context.Context, user string) ([]Route, er func (b *boltRouteStorage) Put(ctx context.Context, r Route) (Route, error) { if r.ID == "" { r.ID = uuid.New() + r.CreatedAt = time.Now() + r.Active = true } err := b.db.Save(&r) diff --git a/internal/database/redis.go b/internal/database/redis.go new file mode 100644 index 0000000..94a2094 --- /dev/null +++ b/internal/database/redis.go @@ -0,0 +1,151 @@ +package database + +import ( + "encoding/json" + "time" + + "github.com/Xe/uuid" + "github.com/brandur/simplebox" + "github.com/garyburd/redigo/redis" + "golang.org/x/net/context" +) + +const ( + redisCertPrefix = "routed:cert:" + redisRoutePrefix = "routed:route:" + redisTokenPrefix = "routed:token:" +) + +type RedisStorage struct { + pool *redis.Pool + sb *simplebox.SimpleBox + + cs *redisCertificateStorage + rs *redisRouteStorage + ts *redisTokenStorage +} + +type redisCertificateStorage struct { + *RedisStorage +} + +type redisRouteStorage struct { + *RedisStorage +} + +func (r *redisRouteStorage) Get(ctx context.Context, id string) (Route, error) { + conn := r.pool.Get() + defer conn.Close() + + data, err := redis.Bytes(conn.Do("GET", redisRoutePrefix+id)) + if err != nil { + return Route{}, err + } + + result := Route{} + err = json.Unmarshal(data, &result) + if err != nil { + return Route{}, err + } + + return result, nil +} + +func (r *redisRouteStorage) GetHost(ctx context.Context, host string) (Route, error) { + conn := r.pool.Get() + defer conn.Close() + + key, err := redis.String(conn.Do("GET", redisRoutePrefix+"host:"+host)) + if err != nil { + return Route{}, err + } + + data, err := redis.Bytes(conn.Do("GET", key)) + if err != nil { + return Route{}, err + } + + result := Route{} + err = json.Unmarshal(data, &result) + if err != nil { + return Route{}, err + } + + return result, nil +} + +func (r *redisRouteStorage) GetAll(ctx context.Context) ([]Route, error) { + return nil, ErrNotImplemented +} + +func (r *redisRouteStorage) Put(ctx context.Context, rr Route) (Route, error) { + if rr.ID == "" { + rr.ID = uuid.New() + rr.CreatedAt = time.Now() + rr.Active = true + } + + rr.EditedAt = time.Now() + + data, err := json.Marshal(&rr) + if err != nil { + return Route{}, err + } + + conn := r.pool.Get() + defer conn.Close() + + key := redisRoutePrefix + rr.ID + + _, err = conn.Do("SET", key, data) + if err != nil { + return Route{}, err + } + + _, err = conn.Do("SET", redisRoutePrefix+"host:"+rr.Hostname) + if err != nil { + return Route{}, err + } + + return rr, nil +} + +func (r *redisRouteStorage) Delete(ctx context.Context, rr Route) (Route, error) { + conn := r.pool.Get() + defer conn.Close() + + key := redisRoutePrefix + rr.ID + + dr, err := r.Get(ctx, rr.ID) + if err != nil { + return Route{}, err + } + + _, err = conn.Do("DEL", key) + if err != nil { + return Route{}, err + } + + _, err = conn.Do("DEL", redisRoutePrefix+"host:"+dr.Hostname) + if err != nil { + return Route{}, err + } + + return dr, nil +} + +type redisTokenStorage struct { + *RedisStorage +} + +// Certs gets the certificate storage interface. +func (r *RedisStorage) Certs() Certs { return r.cs } + +// Routes gets the route storage interface. +func (r *RedisStorage) Routes() Routes { return r.rs } + +// Tokens gets the token storage interface. +func (r *RedisStorage) Tokens() Tokens { return r.ts } + +// Close cleans up resources for this Storage. +func (r *RedisStorage) Close() error { return r.pool.Close() } diff --git a/internal/database/redis_test.go b/internal/database/redis_test.go new file mode 100644 index 0000000..27d0b29 --- /dev/null +++ b/internal/database/redis_test.go @@ -0,0 +1,31 @@ +package database + +import "testing" + +func TestRedisStorageIsStorage(t *testing.T) { + var i interface{} = new(RedisStorage) + if _, ok := i.(Storage); !ok { + t.Fatalf("expected %t to implement Storage", i) + } +} + +func TestRedisCertificateStorageIsCerts(t *testing.T) { + var i interface{} = new(redisCertificateStorage) + if _, ok := i.(Certs); !ok { + t.Fatalf("expected %t to implement Certs", i) + } +} + +func TestRedisRouteStorageIsRoutes(t *testing.T) { + var i interface{} = new(redisRouteStorage) + if _, ok := i.(Routes); !ok { + t.Fatalf("expected %t to implement Routes", i) + } +} + +func TestRedisTokenStorageIsTokens(t *testing.T) { + var i interface{} = new(redisTokenStorage) + if _, ok := i.(Tokens); !ok { + t.Fatalf("expected %t to implement Tokens", i) + } +}